1. 程式人生 > >動態規劃的基礎篇1--最大連續子序列和

動態規劃的基礎篇1--最大連續子序列和

上篇已經稍微介紹了什麼是dp,接下來就是實戰了。今天七夕節,祝願大家有人陪伴,好好珍惜。。哎。。

給定一個數字序列A1,A2,A3,A4,A5,A6,A7,A8,A9.....An。求i,j(1<=i<=j<=n)使得Ai++++++Ai最大,輸出這個最大和

樣例:

-2  11 -4   13 -5 -2

顯然11+(-4)+13=20為和最大的選取情況,因此最大和為20.

下面介紹動態的做法,複雜度O(n),我們會發現其實左端點的列舉是沒有必要的。。

步驟1:令狀態dp[i]表示以A[i]作為末尾的連續序列的最大和(這裡是說A[i]必須作為連續序列的末尾)。以樣例為列:序列

-2 11 -4 13 -5 2,下標分別記為0,1,2,3,4,5,那麼

dp[0]=-2;

dp[1]=11

dp[2]=(11+(-4))=7;

dp[3]=(11+(-4)+13)=20

dp[4]=(11+(-4)+13+(-5))=15

dp[5]=13;

步驟2:做如下考慮:因為dp[i]要求是必須A[i]結尾的連續序列,那麼只有兩種情況

1.這個最大和的連續序列只有一個元素,即以A[i]開始,以A[i]結尾。

2.這個最大和連續序列有多個元素,即從前面某處A[p]開始(p<i),一直到A[i]結尾。

對於第一種情況,最大和就是A[i]本身。

對於第二種情況,最大和就是dp[i-1]+A[i];

由於只有這兩種情況,於是得到轉移轉移方程;

dp[i]=MAX{dp[i],dp[i-1]+A[i]}

這個式子只和i與i以前的元素有關,且邊界dp[0]=A[0],由此從小到大列舉i,即可得到整個dp陣列,接著輸出dp[0],dp[1],....dp[n-1]中的最大值即為最大連續序列的和。

-------------------------code---------------------------------------------------------

int A[maxn],dp[maxn];//從A[i]存放序列,dp[i]存放以A[i]結尾A[i]結尾的連續序列的最大和。

int main(){

int n;

scanf("%d",&n);

for(int i=0;i<n;i++)

scanf("%d",&A[i]);

//邊界

dp[0]=A[0];

for(int i=1;i<n;i++)

//狀態轉移方程

dp[i]=max(A[i],dp[i-1]+A[i]);

//dp[i]存放以A[i]結尾的連續序列的最大和,需要遍歷i得到的才是結果。

int k=0;

for(int i=1;i<n;i++){

if(dp[i]>dp[k]){

k=i;

}

}

printf("%d\n",dp[k]);

}

//廢話一句,至於讓我們去求這裡的連續序列的話,我們已經求出下邊啦,那麼久知道A[i]的下標,一個While(dp[k]!=0),每次都遍歷往前減。

事實上,如何設計狀態和狀態轉移方程,才是動態規劃的核心。