HDUOJ1024 Max Sum Plus Plus(详解)

HDUOJ1024 Max Sum Plus Plus

题意:

给一个包含n个数的数组,从中选出m个没有交集的区间,使这m个区间的区间和的和最大,求出这个最大值

分析:

其实这个题n的范围如果不是那么大,能用二维dp写的话并不算难
但是n就是1e6那么大,即使m的范围比较小基本也只能写一维dp

f o r ( i = 1... m ) for (i=1...m) for(i=1...m)
     f o r ( j = i . . . n ) for (j=i...n) for(j=i...n)
         d p [ j ] = m a x ( d p [ j − 1 ] + a [ j ] , b e s t [ j − 1 ] + a [ j ] ) dp[j] = max(dp[j - 1] + a[j], best[j - 1] + a[j]) dp[j]=max(dp[j1]+a[j],best[j1]+a[j])

注释中有详解

代码:

#include 
using namespace std;
const int inf = INT_MAX;
const int maxn = 1e6 + 10;
int m, n;
int a[maxn], dp[maxn], best[maxn];
int temp;

int main(int argc, char const *argv[])
{
    while (~scanf("%d%d", &m, &n))
    {
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);

        memset(dp, 0, sizeof dp);
        memset(best, 0, sizeof best);

        for (int i = 1; i <= m; ++i)
        {
            temp = -inf; //temp记录取出i个区间时各个区间和的最大值,所以每多取一个区间temp需要被置为-inf
            for (int j = i; j <= n; ++j)
            {
                dp[j] = max(dp[j - 1] + a[j], best[j - 1] + a[j]); //dp[j]记录从前j个数中取出i个区间时各个区间和的最大值
                best[j - 1] = temp;                                //best[j-1]记录从前j-1个数中取出i个区间时各个区间和的最大值,所以在temp被更新前更新
                //这里是最难理解的,为什么是取出i个区间?那么dp[j]=best[j - 1] + a[j]岂不是可能表示从从前j个数中取出i+1个区间?
                //蒟蒻的我曾想了一晚上...
                //观察状态转移方程我们会发现,每一个dp[j]状态都包含了a[j]
                //1.若temp<=dp[j-1]则temp被dp[j-1]更新,而best[j-1]又是被temp更新,则best[j-1]间接被dp[j-1]更新,所以best[j-1]状态包含a[j-1],a[j-1]和a[j]可以连成一个区间
                //2.若temp>dp[j-1],temp不被dp[j-1]更新,best[j-1]间接被dp[j-2]更新,所以best[j-1]状态包含了a[j-2],此时需要一点思维理解能力了,
                //并不是a[j]和a[j-2]隔空连接,而是a[j-1]的连接权被a[j]取代了
                //此处有点类似用lower_bound和upper_bound找最长单调子序列长度,得到的数组并不一定是最长单调子序列,但数组的长度却是最长单调子序列的长度
                //以上是我的理解,如有误还请指正!!!
                temp = max(temp, dp[j]);
            }
        }

        printf("%d\n", temp);
    }
    return 0;
}

你可能感兴趣的:(DP)