HDU 1024 Max Sum Plus Plus 经典 DP


首先申明:这题数据有很大问题

当你输入都为负数时,程序就会出错

如 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代码:

View Code
#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
*/

 

 本人觉得正确的代码,可能有错误:

View Code
#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;
}

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM