首先申明:這題數據有很大問題
當你輸入都為負數時,程序就會出錯
如 2 3
-1 -2 -3
竟然輸出-3。
數據庫里有都為負數的情況,我用別人AC代碼改了一下測試過了,的確有這情況,但答案貌似是錯的。
又如 2 3
-1 2 -3
竟然輸出1.
這讓我郁悶了很久。
設輸入的數組為a[1...n],從中找出m個段,使者幾個段的和為最大
dp[i][j]表示前j個數中取i個段的和的最大值,其中最后一個段包含a[j]。(這很關鍵)
則狀態轉移方程為:
dp[i][j]=max{dp[i][j-1]+a[j],max{dp[i-1][t]}+a[j]} i-1=<t<j-1
因為dp[i][j]中a[j]可能就自身一個數組成最后一段,或者a[j]與a[j-1]等前面的數組成最后一段。
此題n數據太大,二維數組開不下,而且三重循環,想到狀態轉移方程后還是困難重重。
想想,二維數組不行的話,肯定要壓縮成一維數組:
因為dp[i-1][t]的值只在計算dp[i][j]的時候用到,那么沒有必要保存所有的dp[i][j] for i=1 to m,這樣我們可以用一維數組存儲。
用pre[j]表示j之前一個狀態dp[i-1][]中1-j之間,不一定包含a[j]的最大字段和,然后推dp[i][j]狀態時,dp[i][j]=max{pre[j-1],dp[j-1]}+a[j];
褐色的為了方便理解,其實不存在。
AC代碼:

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define maxn 1000003 #define INF 100000000 int dp[maxn],a[maxn],pre[maxn]; int main() { int n, m, i, j, maxx; while(~scanf("%d%d",&m,&n)) { for(i=1;i<=n;i++) scanf("%d",&a[i]); dp[0]=0; memset(pre,0,sizeof(pre)); for(i=1;i<=m;i++) { maxx =-INF; for(j=i;j<=n;j++)//對於每個i,隨着j的增大,maxx越滾越大 { dp[j]=max(dp[j-1],pre[j-1])+a[j]; pre[j-1]=maxx;//把前一輪的最大值賦給pre; //printf("dp[%d]=%d pre[%d]=%d\n",j,dp[j],j-1,pre[j-1]); if(maxx<dp[j])maxx=dp[j]; } //puts(""); } printf("%d\n",maxx);//最后一輪的最大值就是答案。 //因為上一個循環中對於每個i,隨着j的增大,maxx越滾越大 } //而且pre也是越滾越大的。 return 0; } //給了一組數據,不理解就把所有DP打出來,自己手動模擬一遍,這樣好理解多了 /* 4 7 1 2 -4 5 6 -8 10 */
本人覺得正確的代碼,可能有錯誤:

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define maxn 1000003 #define INF 100000000 int dp[maxn],a[maxn],pre[maxn]; int main() { int n, m, i, j, maxx,ans; while(~scanf("%d%d",&m,&n)) { for(i=1;i<=n;i++) scanf("%d",&a[i]); dp[0]=0;ans=-INF; memset(pre,0,sizeof(pre)); for(i=1;i<=m;i++) { maxx =-INF; for(j=i;j<=n;j++)//對於每個i( 每組),隨着j的增大,maxx越滾越大 ,但i->i+1后,有些maxx不一定越滾越大 { dp[j]=max(dp[j-1],pre[j-1])+a[j]; pre[j-1]=maxx;//把前一輪的最大值賦給pre; //printf("dp[%d]=%d pre[%d]=%d ",j,dp[j],j-1,pre[j-1]); if(maxx<dp[j])maxx=dp[j]; //printf("maxx=%d\n",maxx); } if(ans<maxx)ans=maxx; //puts(""); } printf("%d\n",ans); } return 0; }