vlambda博客
学习文章列表

最大m子段和问题(动态规划(又来填表了....))

1.定义

给定由n个整数(可能为负)组成的序列a1、a2、a3...,an,  以及一个正整数m,要求确定序列的m个不相交子段,使这m个子段的总和最大

如给定一个数组{1,-2,3,4,-5,-6}和一个正整数m=2,明显当两个子段分别为{1}和{3,4}时,得到最大m子段和,最大m子段和为8。


2.思路

可以利用动态规划的思想解决该问题。

定义二维数组dp,令dp[i][j]表示前 j 项所构成 i 子段的最大和,且必须包含着第j项,即以第j项结尾。(这个定义很重要,一定要理解)。

举个例子,如dp[3][4]则表示以a4结尾,并且和a4前面的项所构成的3子段和的最大值。简单来说,就是a0a1a2a3a4中分成3段,包含a4且以a4结尾,这3子段和是最大的。(例如可能是a0、a1、a4这三段)



所以,dp[i][j]总共有两种可能。

1.若a[j]和a[j-1]合成一段,此时                               dp[i][j] = dp[i-1][j] + a[j]

最大m子段和问题(动态规划(又来填表了....))


2.a[j]单独成段,然后往a[j]前面的项找i-1个子段最大和,此时dp[i][j] = dp[i-1][t]+a[j](i-1≤t<j)

最大m子段和问题(动态规划(又来填表了....))

最后取这两种情况中的最大值,赋给dp[i][j]。


3.例子

根据思路,实战一把,例如有一个数组

arr={1,-2,3,4,-5,-6},可以根据以上思路做出下表。例如我们要求图中的星星部分的值,也就是

dp[2][4]的值,首先第一种情况是a[4]与前面的a[3]连成一段,即该种情况下的dp[2][4]的值为dp[2][3]+a[4]=8+(-5) = 3;第二种情况是,a[4]自成一段,并且看看其之前的项中,i-1段最大和为多少,可以看到为7,所以该种情况下的dp[2][4]的值为dp[1][3]+a[4] = 7 + (-5) = -2;取第一种情况与第二种情况中的最大值,为3,填入dp[2][4]中。

最大m子段和问题(动态规划(又来填表了....))

我们可以从上往下,从左往右把整张表填完。

那么,假如要求m=2时的最大子段和为多少时,可以看到第2行中,dp[2][3]的时候最大,为8。

另外找i-1子段的最大和,可以使用滚动辅助数组来完成,不用重新遍历。即,再上一轮填空的过程中,记录j列之前(包括j列)的最大值,以供此轮填表使用。


4.参考代码

最大m子段和问题(动态规划(又来填表了....))

IT界的泥石流与你一同成长