最大子段和或稱為最大部分和(maximum subtotal)問題,以下簡稱ms。
舉例說明
例如:
暴力破解(brute force):
可以從串的任意位置開始在連續的任意位置結束,一層迴圈控制起始位置,一層迴圈控制結束位置。
複雜度:o(n^2)
//迭代
#include
#include
using
namespace std;
const
int maxnum =
100001
;const
int mininf =
-1000003
;int numn;
int sequence[maxnum]
;int
main()
for(
int i =
1; i <= numn;
++i)
} cout<
<
}return0;
}
動態規劃(dynamic programming):令b[j]表示以位置 j 為終點的所有子區間中和最大的乙個
子問題:如j為終點的最大子區間包含了位置j-1,則以j-1為終點的最大子區間必然包括在其中
如果dp[j-1] >0, 那麼顯然dp[j] = dp[j-1] + seq[j],用之前最大的乙個加上a[j]即可,因為seq[j]必須包含
如果dp[j-1]<=0,那麼dp[j] = seq[j] ,因為既然最大,前面的負數必然不能使你更大
對於這種子問題結構和最優化問題的證明,可以參考演算法導論上的「剪下法」,即如果不包括子問題的最優解,把你假設的解粘帖上去,會得出子問題的最優化矛盾.證明如下:
令seq[x,y]表示seq[x]+…+seq[y] , y>=x
假設以j為終點的最大子區間 [s, j] 包含了j-1這個位置,以j-1為終點的最大子區間[ r, j-1]並不包含其中
即假設[r,j-1]不是[s,j]的子區間
存在s使得seq[s, j-1]+a[j]為以j為終點的最大子段和,這裡的 r != s
由於[r, j -1]是最優解, 所以a[s,j-1]
得到狀態轉移方程:dp[i] = max(seq[i], dp[i-1]+seq[i]) | 1 <= j <= n && dp[i] >= 0;
seq[i] | dp[i] < 0;
例如,若a序列為(-2,11,-4,13,-5,-2),dp[0]=0,求其他元素如下:
(1)dp[1]=max=max=-2
(2)dp[2]=max=max=11
(3)dp[3]=max=max=7
(4)dp[4]=max=max=20
(5)dp[5]=max=max=15
(6)dp[6]=max=max=13
其中,dp[4]=20為最大值,向前找到dp[1]小於等於0,所以由a2~a4的元素即(11,-4,13)構成最大子段和,其和為20
複雜度:o(n),由上式可以看出,如果dp[i]為負數,就沒有在賦能的意義了,所以dp[i]陣列可以不需要,空間複雜度:s(1)。
#include
#include
using
namespace std;
const
int mininf =
-1000003
;int numn;
int maxnum;
intmain()
if(tempsum <0)
maxnum =
max(maxnum, tempsum);}
cout<
}return0;
}
分治(divide and conquer):產生最大子段和可以由三種情況得出:
hint:合併的過程要是連續的
複雜度:t(n) = 2t(n/2) + o(n);即:o(nlgn)。
#include
#include
using
namespace std;
const
int maxnum =
100001
;const
int mininf =
-1000003
;int numn;
int sequence[maxnum]
;int
mergemax
(int x,
int y,
int z)
intmaxsum
(int left,
int right)
else
int maxnum2 = mininf;
int tempsum2 =0;
for(
int i = mid+
1; i <= right;
++i)
sum = maxnum1+maxnum2;
sum =
mergemax
(sum, leftsum, rightsum);}
return sum;
}int
main()
cout<<
maxsum(0
, numn)
<
}return0;
}
問題大意:給定乙個矩陣,求最大值子矩陣。
我們可以對矩陣向下疊加轉化為最子段和問題,即當前點為末位邊角元素所有矩陣的最大和:這樣就可以對行不斷向下疊加操作行次求解子段最大和便得到結果。
//poj1050為例
#include
#include
#include
const
int maxnum =
101;
const
int mininf =
-100003
;int dp[maxnum]
;int matrix[maxnum]
[maxnum]
;int numn;
int maxnum;
using
namespace std;
intmain()
if(tempsum <0)
maxnum =
max(maxnum, tempsum);}
}}cout<
}return0;
}
最大子段和詳解
問題的提出 給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的子段和的最大值。當所給的整均為負數時定義子段和為0,依此定義,所求的最優值為 max,1 i j n 例如,當 a1,a2,a3,a4,a4,a6 2,11,4,13,5,2 時,...
最大子段和詳解
最大子段和問題 maximum interval sum 有時也稱lis 經典的動態規劃問題,幾乎所有的演算法教材都會提到.本文將分析最大子段和問題的幾種不同效率的解法,以及最大子段和問題的擴充套件和運用.一.問題描述 給定長度為n的整數序列,a 1 n 求 1,n 某個子區間 i j 使得a i ...
最大子段和問題
給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的子段和的最大值。當所給的整均為負數時定義子段和為0 分治法 分析 首先將陣列分為兩部分,最大子段和 可以在陣列的左半部分也可以在右半部分,也可以橫跨分割點,因此我們只需要用分治思想求出左邊最大...