题意是要在一段数列中求 m 段互不重合的子数列的最大和。
动态规划,用数组 num[ ] 存储所给数列,建二维数组 dp[ ][ ] , dp[ i ][ j ] 表示当选择了第 j 个数字( num [ j ] )时,前 j 个数字被分成 i 组的所得最大和。
那么这个最大和等于 max{ ( 前 i - 1 组的和 + 第 i 组(含num[ j - 1]) + num[ j ] ),( 前 i - 1 组的和 + num[ j ] ) };
即 dp[ i ][ j ] = max( dp[ i ][ j - 1], dp[ i - 1 ][ k ] ) + num[ j ];
但是这么大的二维数组开不了的,而且每次算当前状态时只需要前一状态,再之前的没什么用,(即状态具有后无效性,前面的选择不会影响后续选择)因此使用滚动数组,再干脆直接开两个一维数组,dp[ ] 和 pre[ ],pre[ j - 1 ] 表示 j - 1 之前的数的最大和
( 不包括 num[ j - 1 ] ) ,dp[ j ] 表示选择了 num[ j ] 时前 j 个数字的最大和,
则 dp[ j ] = max( dp[ j - 1 ] ,pre[ j - 1 ] ) + num [ j ];
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1000000; 4 int dp[maxn],pre[maxn],num[maxn]; 5 int main() 6 { 7 int n,m,tmp; 8 while(~scanf("%d%d",&m,&n)) 9 { 10 for(int i = 1; i <= n; ++i) 11 scanf("%d",&num[i]); 12 memset(dp,0,sizeof(dp)); 13 memset(pre,0,sizeof(pre)); 14 for(int i = 1; i <= m; ++i) 15 { 16 tmp = -10000000; 17 for(int k = i; k <= n; ++k) 18 { 19 dp[k] = max(dp[k-1],pre[k-1]) + num[k]; 20 pre[k-1] = tmp; 21 tmp = max(tmp,dp[k]); 22 } 23 } 24 printf("%d ",tmp); 25 } 26 return 0; 27 }