HUD 1024 Max Sum Plus Plus (滚动数组)

题意:从一个序列中选出分成不交叉的m段 的最大和

解析 : 题目中 1 <= n <=1000000 所以二维数组是不能用了  所以 要想到简化为一维

dp[i][j]表示以i结尾的前i个数 分成j组的最大和  对于一个数A[i] 我们有两种选择,一是与第(i-1)个数在一组 或者 自成一组  ,所以状态方程就出来了

dp[i][j] = max(dp[i-1][j], max(dp[k][j-1] {k| 1<= k <= i-1} ))+A[i];  

max(dp[k][j-1] {k| 1<= k <= i-1})表示前i-1个数组成的j-1组的最大值

这道题没有说m是多少  所以比较尴尬。。。 又因为每个状态只与它一个状态有关,那么就用滚动数组好了 

 maxx = max(maxx, dp[k^1][i-1]);  // 前(i-1)个 分成(k-1)组的最优解

异或^是相同为0,不同为1,可以用^1来转换状态

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

 滚动数组讲解:https://www.cnblogs.com/WTSRUVF/p/9210633.html

 

具体详情见代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 1001000, INF = 0x7fffffff;
int A[maxn], dp[2][maxn];
int main()
{
    int m, n;
    while(~scanf("%d%d",&m,&n))
    {
        mem(dp, 0);
        mem(A, 0);
        int k =0;               // 初始化为0
        for(int i=1; i<=n; i++)
            scanf("%d",&A[i]);
        int maxx, ret;
        for(int j=1; j<=m; j++)
        {
            k ^= 1;           //因为只与j和j-1两个状态有关  所以每次都要异或
            maxx = dp[k^1][j-1];    //maxx的意义为 前j-1个数 分成k-1组的最优解 又第j组最小是j个数  所以每次的maxx开始值为  dp[j-1][j-1]  即 dp[k^1][j-1]
            dp[k][j] = dp[k^1][j-1] + A[j];  // 因为选择第i个数,分成i段,所以只能自己成一段,那么只能这样写;
            ret = dp[k][j];           //ret 为这些数分成k组后最大的值  开始值为dp[k][j];
            for(int i=j+1; i<=n; i++)
            {
                maxx = max(maxx, dp[k^1][i-1]);
                dp[k][i] = max(dp[k][i-1], maxx) + A[i];
                ret = max(ret, dp[k][i]);
            }
        }
        printf("%d\n",ret);

    }

    return 0;
}

 

 

 

 

 

posted @ 2018-05-20 10:01  WTSRUVF  阅读(239)  评论(0编辑  收藏  举报