HDU - 1024 Max Sum Plus Plus (kuangbin - 基础DP)

这篇博客介绍了一个动态规划的问题,要求在n个数中找到m个子段的最大和。博主分析了动态规划的状态转移方程,并指出常规方法的时间复杂度为O(n^3),提出了使用b数组优化到O(n^2)的方法,详细解释了优化思路,并提供了代码实现。
摘要由CSDN通过智能技术生成

题目描述 (已转换成中文)

  你有n个数s1, s2…sn,给你一个整数m,求m个子段和的最大值

输入格式

  输入m,输入n。后面跟着输入n个ai (n < 1e6)

输出格式

  输出最大和

输入输出样例
输入

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

输出

6
8

题目链接

分析:

  这道题大概的意思就是把n个数中,切成m段,求这m段的最大字段和,属于动态规划的题目,重点是找出转移方程。
  先来分析下如何得到状态方程:使用一个二维数组dp[i][j]表示如果取第j个数时,前j个数(包括第j个数)划分成i段的最大值,所以此时会出现两种情况:(1)、第j个数直接被并到第i段里边,此时的转移方程:dp[i][j] = d[i][j - 1] + a[j] ; (2)、第j个数没有被划分进第i段内,即第j个数独自成为第i段,既然第j个元素没有被划分在第i段内,说明前j - 1个元素被划分成了i - 1段。被划分成i - 1段至少需要i - 1个元素,最多j - 1个元素。(因为当前只有j - 1个元素可用)。所以此时需要枚举从i - 1开始,到j - 1结束这些状态,求出这些数划分成i - 1段时,哪种状态得到的i - 1个子段的和是最大的。所以此种情况的转移方程:dp[i][j] = max(dp[i - 1][k]+ a[j]),k满足:i - 1 <= k <= j - 1。综合两种情况,动态转移方程:
dp[i][j] = max(dp[i][j - 1] + a[j], max(dp[i - 1][k] + a[i]));

这道题需要注意的地方:

  但是这个做法会产生一个问题,DP时的时间复杂度的O(n ^ 3),n的数据范围是1e6,如果直接暴力得到二维数组dp,绝对会超时,所以我们需要dp做法进行优化,由前面的分析我们得到的动态转移方程式:dp[i][j] = max(dp[i][j - 1] + a[j], max(dp[i - 1][k] + a[i])),我们发现每一次得到dp[i][j]时,max(dp[i - 1][k] + a[k])中有用到的只有前i - 1段的dp数组,就是在遍历找上一个状态被划分成i - 1段之后的最大值,那么可以进行优化了,在每一次递推得到dp[i][j]的时候,专门使用一个b数组记录一段数中的最大dp值(b[j]表示在前j个数划分成i个子段时的最大和),所以这样在下一层循环中(第i++层),通过b[j - 1] + a[j]就可以表示前j - 1个数被分成前i - 1段并且第j个数独自成为一段时的最大子段和(上述的第二种情况),这样就优化了一层for循环。时间复杂度下降了一个维度。对于状态方程:dp[i][j] = max(dp[i][j - 1] + a[j], max(dp[i - 1][k] + a[i]))中的dp[i][j - 1] + a[i]可以直接表示成dp[j - 1] + a[i],所以,最终的转移方程:dp[i] = max(dp[i - 1] + a[i], b[i - 1] + a[i])),然后再加上我们需要维护的一些信息,更新即可。

列举两个图来方便理解:

具体的转移方程是这样得来的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值