最大序列片斷和
定義1對於乙個序列a= 來說,其片斷和s[i] [j] = ∑ak | i <= k <= j。
那麼有了片斷和的定義,片斷和又怎麼求呢?先來看乙個基本的題目:
例題1
題目描述
給出乙個序列a=,求它的最大片斷和。
輸入
輸入第一行為乙個整數n(1<=n<=1000000),第二行包含n個整數。這n個整數的和的絕對值不超過2^31。
輸出
乙個整數為序列a的最大片斷和。這個題目我想大家已經都不陌生了。解決的方法是用貪心。我還是**一下。
假設我們要的最大片斷和為s[i][j] (i < j )。那麼我們保證不會存在s[i] [k] < 0 ( k < j )。因為如果存在這樣的情況,那麼片斷和s[k + 1] [j] = s [i] [j] – s [i] [k] > s [i] [j]。和假設矛盾。
在下面的演算法中,如果存在了一段s[i] [k] < 0 ,我們肯定不會用這段,將其捨掉。下面的演算法中不會出現s [p] [k] > 0 ( p < i )。所以演算法是正確的。
最大片斷和的求法(源程式)#include
int n , maxsegment;
int num [1000000];
main ()
cout << maxsegment;
system ( "pause" );
}然後我們看下乙個例題(pku2479)。
例題2
題目描述
給出乙個序列a=,如下定義乙個函式d(a):
t1 t2
d(a) = max
i=s1 j=s2
你的任務就是計算d(a )。
輸入
第一行是測試資料組數t(<=30)。然後是t組測試資料。每組資料報含乙個整數n(2<=n<=50000)。第二行包含n個整數a1, a2, ..., an. (|ai| <= 10000)。之後是一行空行。
輸出
每組資料乙個整數d(a)。各佔一行。
簡單的說,就是求兩段不相交的片斷和最大是多少。有兩種解決辦法:第一種仍然沿用貪心策略。第二種用動態規劃方法解決。
因為這兩個最大的片斷一定會和單個最大片斷有關。我們可以求出最大片斷並記錄最大片斷所在的位置。然後有兩部分:第一,求出除了這個最大片斷以外的剩餘部分中的最大片斷,兩者加和;第二,將這個最大片斷分成兩份(就是在最大片斷中找出一段部分和最小的部分,和求部分和類似)。貪心的效率為o(n)。
第二種方法是dp。用maxsegment1[i] 表示以子串行的最大片斷和。這個在上面的過程中記錄一下即可。
用maxsegment2 [i]表示以ai結尾的兩段子序列的最大和,那麼規劃方程為:
maxsegment2 [i] = max + ai | ( i > 2 , maxsegment2 [i] = a1 + a2 )}
這裡ai有兩種選擇,要麼獨立乙個片斷maxsegment1[i – 1] + ai,要麼與前面的ai-1一起組成乙個片斷(maxsegment2 [i – 1] + ai)。
時間複雜度為o(n)。
接下來你一定發現,這個dp方法的擴充套件性非常的好,它可以應用到多個片斷。假設我們要求乙個序列的m不相交片斷和的最大值,甚至可以用maxsegment[i] [j] 表示前j個數以aj結尾的最大i片斷和。然後對上面的遞推做適當的修改即可。時間複雜度為o(n×m)。
下面的題目就是這樣的乙個題,如果有時間不妨試一下:
最大序列和
輸入描述 第一行為乙個正整數n,第二行為n個整數,表示序列中的數。輸出描述 輸入可能包括多組資料,對於每一組輸入資料,僅輸出乙個數,表示最大序列和。輸入例子 5 1 5 3 2 4 61 2 3 4 10 6 4 3 1 2 5輸出例子 9 7 1 include using namespace s...
最大序列和
給出乙個整數序列s,其中有n個數,定義其中乙個非空連續子串行t中所有數的和為t的 序列和 對於s的所有非空連續子串行t,求最大的序列和。變數條件 n為正整數,n 1000000,結果序列和在範圍 2 63,2 63 1 以內。第一行為乙個正整數n,第二行為n個整數,表示序列中的數。輸入可能包括多組資...
最大序列和
給出乙個整數序列s,其中有n個數,定義其中乙個非空連續子串行t中所有數的和為t的 序列和 對於s的所有非空連續子串行t,求最大的序列和。變數條件 n為正整數,n 1000000,結果序列和在範圍 2 63,2 63 1 以內。第一行為乙個正整數n,第二行為n個整數,表示序列中的數。輸入可能包括多組資...