HDU 1024 (DP,有空在写一遍)

本文介绍了一个经典的区间划分问题,通过动态规划求解最优解,并采用一种优化策略将时间复杂度从O(m*n^2)降低到O(m*n)。文章提供了完整的C++代码实现。

题意还是很简单的,就是给你n个数,把他分成m个独立的区间,要求所有区间的和最大

那么我们很容易想到递推方程

dp[j][i]表示前j个数分成i个区间的最大和且以a[j]结尾

递推方程就为dp[j][i]=max(dp[j-1][i]+a[j],max(dp[t][i-1]+a[j]))   (i-1<=t<=j)

可以看到我们这个方程的时间复杂度为 m×n×n,因为n=1e6所以时间复杂度炸了

然后我们发现dp[j][i]只与dp[j-1][i],和dp[*][i-1]的最大值有关

那么我们在求i-1的时候保留最大值就好了呀

这就成功的把时间复杂度降到m×n了

接下来正片开始

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#define maxn 1001000

using namespace std;
long long dp[maxn],num[maxn],mmax[maxn],sum[maxn];
int main()
{
    int m,n;
    long long mmmax;
    while(~scanf("%d %d",&m,&n))
    {
        sum[0]=0;
        for (int k=1;k<=n;k++)
        {
            scanf("%lld",&num[k]);
            mmax[k]=0;
            dp[k]=0;
        }
        dp[0]=0;
        mmax[0]=0;//初始化是全部设为0
	//因为对于第一个dp[1]他要用到的是dp【0】和mmax【0】嘛
	//然后对于i=1时的每一个dp【j】他前面就是相当于max(dp【j-1】【0】)取0的话当然是0咯

        for (int i=1;i<=m;i++)
        {
            mmmax=-0x3f3f3f3f;
            for (int j=i;j<=n;j++)
            {
                dp[j]=max(dp[j-1]+num[j],mmax[j-1]+num[j]);
		//原来的方程是dp[j][i]=max(dp[j-1][i]+a[j],max(dp[t][i-1]+a[j]))   (i-1<=t<=j)
		//dp[j]=dp[j][i] mmax[j-1]=max(dp[t][i-1]) 0<=t<=j-1

                mmax[j-1]=mmmax;//这个mmax[j-1]是给下一个i用的哦
                mmmax=max(mmmax,dp[j]);//然后我们更新mmmax的值,就是dp[i]到dp[j]的最大值
            }
        }
        printf("%lld\n",mmmax);//注意不是输出dp[n]哦,因为dp[n]是以n结尾的
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值