码迷,mamicode.com
首页 > 其他好文 > 详细

51nod1052 最大M子段和

时间:2018-01-27 11:23:59      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:表示   math   opened   code   define   style   src   closed   pac   

很经典的动态规划,Maxsum Plus

dp[i][j]表示将i个数字,分为j的段不相交子段的最大字段和,容易得到:

  dp[i][j] = max(dp[i-1][j],dp[k][j-1])+a[i] k∈[j-1,i]

因为数据范围过大,对其方程式进行压缩:

  dp[i-1][j]+a[i] 表示:将a[i]直接划入最后一个子段,字段数目不变

  dp[k][j-1]+a[i]表示:将a[i]看做一个新增的子段,子段数目为原有子段数目+1

  列出伪代码如下:

  for(j=1;j<=m;j++)//枚举字段数

  {

    LL maxn = pre[j-1] //maxn存放 dp[k][j-1] (k为变量)的最大值

    for(int i=j;i<=n-m+j;i++) //枚举能划分为j段的数字个数

    {

      dp[i] = max(dp[i-1],maxn)+a[i]  //相当于从 (dp[i-1][j]+a[i],dp[k][j-1]+a[i])中选取最大值

      if(maxn < pre[i]) //pre[i]用来存放,i个字符划分为不相交j-1段的最大字段和,故而应先更新maxn再更新pre

        maxn = pre[i];

      pre[i] = dp[j];//更新pre值

    }

  }

 

AC代码:

技术分享图片
#include<stdio.h>
#include<math.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MAXSIZE 1000005
#define INF 999999999
#define LL long long
using namespace std;

LL dp[MAXSIZE],pre[MAXSIZE],a[MAXSIZE];

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<=m;i++)
        {
            LL maxn = pre[i-1];
            for(int j=i;j<=n-m+i;j++)
            {
                dp[j] = max(dp[j-1],maxn)+a[j];
                if(maxn < pre[j])
                    maxn = pre[j];
                pre[j] = dp[j];
            }
        }
        LL ans = 0;
        for(int i=m;i<=n;i++)
        {
            if(ans < dp[i])
                ans = dp[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

51nod1052 最大M子段和

标签:表示   math   opened   code   define   style   src   closed   pac   

原文地址:https://www.cnblogs.com/alan-W/p/8364873.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!