動態規劃(dynamic programming, dp)為一常用演算法思想,本文講述如何利用dp解決常見的最大欄位和及其變種問題。
設陣列為a[k],1≤k≤n,最大欄位和x定義為:
x=max1≤i≤j≤n???∑k=ija[k]???
x直觀含義即,求任一連續字陣列的最大和。
不妨設:
b[j]=max1≤m≤j???∑k=mja[k]???
其中,1≤j≤n
b[j]的直觀含義為,以a[j]為結束元素的連續陣列的最大和。
由x和b[j]的定義,易知:
x=max1≤j≤nb[j]
這也很好理解。設想一下,所求得的連續字陣列肯定以某個元素結束,求出所有的「以某個元素結束的連續陣列最大和b[j]」,取其最大的b[j],即為x。
下面求b[j]。
(1) 當b[j−1]>0時,無論a[j]為何值,b[j]=b[j−1]+a[j];
(2)當b[j−1]≤0時,無論a[j]為何值,b[j]=a[j];
k 1
2 3
4 a[k]
3 -4
2 10
b[k]
3 -1
2 12
已知陣列a[k],求b[j],b[j]的含義可以參考上面的定義。通過上述給出的演算法,可以求得b[j]如下。
其中,b[1]=a[1],b[2]=b[1]+a[2],b[3]=a[3],b[4]=b[3]+a[4];因此,對陣列a,最大欄位和為b[4],即x=12。
求x,即最大欄位和的**。
int b[n + 1];
b[1] = a[1];
int x= a[1];
for(int i = 2; i <= n; i++) else
if(b[i] > x)
x = b[i];
}演算法時間複雜度為o(n)。
設陣列a[t],1≤t≤n,兩個不重疊連續字陣列的最大和s定義為:
s=max1≤i≤j
應用了求最大欄位和的方法。其求解演算法如下:
(1)從頭到尾掃瞄一遍陣列,其迴圈下標i從1增加到n,依次求得字陣列a[1…i]的最大欄位和,將結果儲存在maxsum[1…n]陣列;
(2)從尾到頭掃瞄一遍陣列,其迴圈下標i從n減小到1,依次求得字陣列a[i…n]的最大欄位和,將結果儲存在rmaxsum[1…n]陣列;
(3)從尾到頭掃瞄一遍陣列(其實哪個方向無所謂),其迴圈下標從n−1到1,求和maxsum[i]+rmaxsum[i+1],取最大的結果,即max,1≤i≤n−1,即為所要求的結果。
t 1
2 3
4 a[t]
3 -4
2 10
b[t]
3 -1
2 12
maxsum[t]
3 33 12
rb[t]
11 8
12 10
rmaxsum[t]
12 12
12 10
其中,rb陣列與b陣列的作用類似,只不過rb[j]儲存的是「從尾到頭方向,以a[j]元素為結束元素的連續陣列的和的最大值」。而rmaxsum同樣只需根據rb陣列即可求出。
以poj上面2593題「max sequence」為例給出相應的**。
#include
const int max = 100005;
int arr[max];
// 儲存字陣列的最大欄位和,分正向和反向
int maxseqhere[max], rmaxseqhere[max];
// 儲存「以某個元素為結束元素的字陣列」的最大和,同樣分正向和反向
int maxendinghere[max], rmaxendinghere[max];
int main()
// 以下從頭到尾掃瞄陣列,求得字陣列的最大欄位和
maxendinghere[0] = arr[0];
maxseqhere[0] = arr[0];
int maxtemp = arr[0];
for(int i = 1; i < n - 1; i++) else
if(maxendinghere[i] > maxtemp)
maxtemp = maxendinghere[i];
maxseqhere[i] = maxtemp;
}// 以下從尾到頭掃瞄陣列,求得字陣列的最大欄位和
rmaxendinghere[n - 1] = arr[n - 1];
rmaxseqhere[n - 1] = arr[n - 1];
int rmaxtemp = arr[n - 1];
// 儲存輸出結果
int maxsumoutput = rmaxseqhere[n - 1] + maxseqhere[n - 1 - 1];
for(int i = n - 2; i > 0; i--) else
if(rmaxendinghere[i] > rmaxtemp)
rmaxtemp = rmaxendinghere[i];
rmaxseqhere[i] = rmaxtemp;
// 直接在反向掃瞄中求maxsumoutput即可,不用再多一次掃瞄
if(rmaxseqhere[i] + maxseqhere[i - 1] > maxsumoutput)
maxsumoutput = rmaxseqhere[i] + maxseqhere[i - 1];
}printf(%d
, maxsumoutput);
}return 0;
求解最大欄位和
演算法1 窮舉法,對所有的 i,j 對,順序求和a i a j 並比較出較大的和 演算法2 分治法,將陣列分成左右兩半,分別計算左邊的最大和 右邊的最大和 跨邊界的最大和,然後比較其中的最大者。演算法3 動態規劃法 include include 窮舉法求出所有子段和的情況,比較得到較大值 o n ...
最大欄位和求解方法
問題描述 給定n個整數 可能有負數 組成的序列a1,a2,an,求該序列的最大子段和。如果所有整數都是負數,那麼定義其最大子段和為0。方法一 暴力雙重迴圈破解法 方法二 遞迴分治 在陣列的 center right left 2 left 位置處分開。形成兩個子陣列。那麼,最大子段和 可能出現在三個...
暴力法 分治法 動態規劃法求解最大欄位和
實驗專案4 最大子段和問題 發現這個博主的 實在是太棒了 1.問題分析 給定由n個整數 可能有負整數 組成的序列 2.演算法設計思路 暴力法 對於起點 i,遍歷所有長度為1,2,n i 1的子區間和,遍歷所有的字段,找出最大欄位和。分治演算法 求解區間及其最大和,從結構上是非常適合分治法的,因為所有...