主要参考这篇文章
http://hi.baidu.com/eizi/blog/item/3c12270987a4ad38e9248880.html
题意:
给你n个数的序列,从中取m段不相交的序列[ai,bi](1<=i<=m)使得这m段的和是所有可能中和最大的.
思路:
用dp[i][j]表示第i段以j结尾的最大值,两种情况:(1).将j连到以j-1为结尾的第i段后面;(2).a[j]单独作为第i段,那么第i-1段可能以i-1.....j-1 结尾.
状态转移方程: dp[i][j]=max{dp[i][j-1]+a[j] , dp[i-1][k]+a[j](i-1<=k<j) };
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
dp[i][j]=dp[i][j-1]+a[j];
for(k=i-1;k<j;k++)
dp[i][j]=max{ dp[i][j] , dp[i-1][k]+a[j] };
}
数据范围是1000,000三重循环无疑超时,分析容易知道第i段只和第i-1段的状态有关,
用 f[i] 表示当前处理的 i 段
用 pre[i-1] 表示当前处理之前的 i -1 段
所以 f[i] = max ( f[i-1] , pre[i-1] ) + a[j] ;
#include"stdio.h" #define MAX 1000005 int a[MAX],f[MAX],pre[MAX]; int n,m,maxx; int max(int x,int y) { return x<y?y:x; } int main() { int i,j; while(scanf("%d%d",&m,&n)!=-1) { for(i=1;i<=n;i++) { scanf("%d",&a[i]); pre[i]=f[i]=0; } f[0]=pre[0]=0; for(i=1;i<=m;i++) { maxx=-999999999; for(j=i;j<=n;j++) { f[j]=max(f[j-1],pre[j-1])+a[j]; pre[j-1]=maxx; maxx=max(maxx,f[j]); } } printf("%d\n",maxx); } return 0; }