现在的位置: 首页 > 综合 > 正文

HDU 1024

2017年11月21日 ⁄ 综合 ⁄ 共 1171字 ⁄ 字号 评论关闭

题意:给你一串长度为n的数列,叫你求其中k段子序列的和的最大值。

本人愚笨… 画了一个晚上才搞懂怎么回事……好羞愧…

有几点领悟:博士原先讲说,DP就像填表,你先填行还是先填列都可以。现在有了更深入的理解了。

首先DP思想,对于数列中的一个数,对它进行处理,先设dp[i][j]表示前i个数(包括当前的数)j个子序列的和。有两种情况:

1.当前数的为第i个数,在前i-1个数中,若已取满j段,那么现在要做的就是把当前数纳入其中。

2.若没有取满j段,则一定取了j-1段,也就适合说当前这个数自成一段,(因为若是取的段数小于j-1段的话,就会出现要去前面的数中取段数的事情了,但是我们处理的是当前的这个数)。所以说可以列出状态转移方程:dp[i][j]=max(dp[i-1][j],dp[k][j-1])+a[i].其中,k的范围是[j-1,i-1]。因为要在前i-1个数中找到最大的和,但是序列范围肯定不能比段数来的少。嗯,所以这里dp[i-1][j]表示当前这个数只能并入前一个数的那一段区间。

然后这里有个表格,方便理解。是从  http://blog.csdn.net/skillart/article/details/8677423 这里撸的,十分感谢!从这里看懂的!

比如这么一行数据 3 6 2 3 -7 6 4 -5  所得到的f[i][j]数据如图所示

0 1 2 3
0 0 0 0 0
1 0 2 0 0
2 0 5 5 0
3 0 -2 -2 -2
4 0 6 11 11
5 0 \ 15 15
6 0 \ \ 10

按照表格走,就觉得很好理解了。

到这里可以大致了解原理,然后剩下的就是优化了。

***********************************

没有怎么理解优化,但是这几天有事拖得太久了,先上代码吧。

#include <stdio.h>
#define maxn 1000001
#define inf 0x3fffffff;
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
int min(int x,int y)
{
    if(x>y) return y;
    else return x;
}
int n,m;
    int a[maxn],sum;
    int f[maxn],h[maxn];// help array
int main()
{

    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int i,j,k;
        for(i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                h[i]=f[i]=-inf;
            }
        for(i=1;i<=n;i++)
        {
            k=min(i,m);
            for(j=1;j<=k;j++)
            {
                f[j]=max(f[j],h[j-1])+a[i];
                h[j-1]=max(h[j-1],f[j-1]);
            }
            h[j-1]=max(h[j-1],f[j-1]);
        }
        printf("%d\n",h[m]);
    }
    return 0;
}

抱歉!评论已关闭.