算法优化:最大子段和,最大子矩阵和,一维,二维情况分析,动态规划
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                算法优化:最大子段和,最大子矩阵和,一维,二维情况分析,动态规划
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                最大子段和,前面b[j]理解的是:終點在j的最大連續子段和,及從k:j最大和
是對b[j]進行動態規劃,從k:j最大和:取決于k:j-1的最大和,他大于0的話,就為k:j-1的最大和+arr[j],他小于0的話,就只是arr[j]
終點在j一共有n種情況,原問題只是求b[j]的最大值
從上面可以看出,終點在j的最大連續子段和這個還是很刁鉆的,解決問題你不從原問題直接去分解,而去想“終點在j的最大連續子段和”,怎么會想到了?
馬后炮,可能從兩個方向入手,一是純粹從解析式入手,純推導,分解max的定義域,然后思考實際意義,或者不思考,直接按照數學公式處理:
另外一種思路,從平常的算法入手思考優化,平常算法一般使用兩個指針i和j,i指向子段和起始的位置,j指向子段終止的位置,然后從左往右掃描,這樣原問題可以看成:起始位置為i的最大連續字段和。我們動態規劃得到狀態方程一般需要從n到n-1,一般情況我們需要反過來從后往前處理(參考選與不選我們都是從后往前處理的),也就是原問題可以看成:終止位置為j的最大連續字段和,這也j也可以作為狀態方程的規模變量。
以上的兩種思路,也可把最大子段和推廣到二維上
二維的最大子段和:m*n的矩陣,求最大子矩陣和
第一種思路通過純數學變換:
我們簡化t(i1,i2)
我們假設b[j],簡化如下:
 
看出來了沒有,t(i1,i2)是啥,他是在求數組b的最大子段和,也就是一個一維的最大字段和
回頭再看原問題是啥了:max{t(i1,i2)}, 1<=i1<=i2<=m,這個只是單純的求最大值,雙針遍歷n,找到最大的那個t(i1,i2)
現在對比一維和二維原問題的情況:
一維時:max{b[j]}, 1<=j<=n,b[j]可遞歸
二維時:max{t(i1,i2)},1<=i1<=i2<=m,t(i1,i2)是一個一維的最大子段和,可以通過一維的方式求得。
我們再思考一下其實際的意義,得到第二種思路:一維時,b[j]可理解為終點在j的連續子段和;二維時t(i1,i2)的含義了?子矩陣行起止于(i1,i2),把對應的每一列看成一個元素組成的數組(應該是n個)求得的最大子段和
以上二維的實現方法,也是沒有直接對二維的原問題進行規約得到狀態方程,而是規約為一維的問題,一維的問題也沒有直接使用動態規劃,只是可能解用到了動態規劃
算法時間復雜度O(m^2 * n)或者O(n^2 * m), 實現的時候可以把行列長的用一維的方式解決.
代碼實現如下:
#%% # 動態規劃的算法,狀態方程,初始值 # 如何劃分子問題比較好了,看成選擇問題,選與不選,從尾部開始,i選的話,最大值就是end_max前面 # n-1個元素的最大值+arr[i],不選的話就是前面n-1個元素求最小字段和 # 這個工作量好大,問題規模縮小了1,然后干了分治算法一層的工作量 # 所以這種規約子問題的方案不好? # 最大字段結束在j,那么原問題的解就是j=0,1,2..len(arr)-1 # 這么多情況里面的最大值, # 我們定義b[j]為結束在j字段和最大值,max{b[j]} 0<=j<=len(arr)-1 # 我們只要求出了每一個b[j],最大值就是可以從里面求出來了 # 那么b如何求解了,結束在j的最大字段和,假如前面j-1最大字段和小于0的話,那就是arr[j] # 狀態方程為:b[j] = max{b[j-1]+arr[j],arr[j]} # 這里不需要考慮arr[j]是否大于0,因為我的子問題就是定義的是結束在j的最大字段和,至于 # 最終的解是結束在不同的j上的最大字段和的最大值。# 這個方法可以知道結束位置j,沒法知道起始位置i為多少啊 def maxSumDynamicProgramming(arr):# 本來是需要一個數組來記錄b的,然后找b[]里面的最大值# 但是我們得到一個b,就可以更顯最優結果的,我只要記錄當前最優解就行了,所以只需要當前的b# b的初值就是b[0-1]的值,也就是沒有元素時最大字段和為多少,為0cur_b =0# 用于記錄最優的結果best_result = 0best_j = -1# 根據狀態方程自底向上完成for j in range(len(arr)):# b[j] = max{b[j-1]+arr[j],arr[j]},當b[j-1]>0為左邊,否則為右邊,也可以直接用maxif cur_b>0:cur_b += arr[j]else:cur_b = arr[j]# 每求出一個b,就更新一下當前最優解if cur_b >= best_result:best_result = cur_bbest_j = jreturn best_result,best_j#%% import numpy as np # 處理矩陣,把arr[i1:i2+1,:]轉換成一維數組,也就是把每一列的從i1到i2相加 def matrixSumByRow(arr,i1,i2,n):li = [0]*nfor j in range(n):for i in range(i1,i2+1):li[j] +=arr[i][j]return lidef maxSumOrder2(arr):# 獲取矩陣的行列row,column = arr.shape# 初始化左右結果,best_j1由于一維最大子段和沒有實現,這里也沒有best_result = 0best_i1 = -1best_i2 = -1best_j2 = -1# 原問題max{t(i1,i2)},1<=i1<=i2<=m,遍歷所有的t(i1,i2)for i1 in range(row):for i2 in range(i1,row):# matrixSumByRow(arr,i1,i2,column)把arr[i1:i2+1,:]轉換成一維數組# 求出這個一維數組的最大字段和,這個是原問題的一個可行解t_i1_i2,j2 = maxSumDynamicProgramming(matrixSumByRow(arr,i1,i2,column))# 如果可行解優于當前的最優解,更新為當前最優解if t_i1_i2 > best_result:best_result = t_i1_i2best_i1 = i1best_i2 = i2best_j2 = j2return best_result,[best_i1,best_i2,-1,best_j2]#%% arr = np.full((5,5),-1) arr[1][1] = 4 arr[1][3] = 4 arr[3][1] = 4 arr[3][3] = 4 print(arr) print(maxSumOrder2(arr))arr = np.full((5,5),-1) arr[1][1] = 4 arr[1][3] = 4 arr[3][1] = 4 arr[3][3] = 4 print(maxSumOrder2(arr))[[-1 -1 -1 -1 -1][-1 4 -1 4 -1][-1 -1 -1 -1 -1][-1 4 -1 4 -1][-1 -1 -1 -1 -1]] (11, [1, 3, -1, 3])總結
以上是生活随笔為你收集整理的算法优化:最大子段和,最大子矩阵和,一维,二维情况分析,动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 算法优化:最大字段和,双指针遍历(n^2
- 下一篇: 算法优化:最大m个子段和,问题规模从1个
