1024 多组最大字段和 循环使用优化

来源:互联网 发布:c语言swap 编辑:程序博客网 时间:2024/06/12 10:35

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1024

这道题是最小子段和加强版。hdu1003是求出一组最大字段和,现在是求出m组最大子段和。

Sample Input
1 3 1 2 32 6 -1 4 -2 3 -2 3
 

Sample Output
68

思路:这道题是典型的DP题。刚开始不会,参考了别人的方法。拿别人的图用一下。

http://blog.sina.com.cn/s/blog_677a3eb30100jxqa.html

v

dp[i][j]表示将前j个数分成i段的最优解,且以j为结尾。一种是dp[i][j-1],前j-1个数,已经分成i段,将第j个数字插入。

dp[i][j-1]+a[j].

另外一种情况是第j个数作为第i段插入,找到i-1段中的最优解。即dp[i-1][k](1<=k<j)+a[j]

如图中的例子,将前3个数,分成2组,一种可能是前2个数已经分成2组,-2插入;另外一种是-2作为单独一组插入,寻找i-1段中最大值4.dp[2][3]=2.

接下来判断临界条件。dp[0][j]=0,当i>j时,不存在,因为j个数最多分成j组。

优化:因为每次计算dp[i][j]只是用到dp[i][j-1]和dp[i-1][k],只要保存dp[i-1][k]即可。

#include<stdio.h>#include<algorithm>#include<string.h>#include<iostream>using namespace std;#define INF -99999999#define maxn 1000000int a[maxn + 10];int dp[maxn + 10];int pre[maxn + 10];int main(){int m, n,i,mmax;while (~scanf_s("%d%d", &m, &n)){memset(a, 0, sizeof(a));memset(dp, 0, sizeof(dp));memset(pre, 0, sizeof(pre));for (i = 1; i <= n; i++){scanf_s("%d", &a[i]);                         }for (i = 1; i <= m; i++){mmax = INF;for (int j = i; j <= n; j++){dp[j] = max(dp[j - 1] + a[j], pre[j - 1] + a[j]);//pre[j-1]表示dp[i-1][k]pre[j - 1] = mmax;mmax = max(mmax, dp[j]);//注意这里顺序不能颠倒,如果先更新mmax,再更新pre[j],下次j会直接使用更新了的数据,不是上}                                 //不是上次i-1时的pre[j]了。所以每次使用完pre[j-1]后更新}cout << mmax << endl;}return 0;}


 

原创粉丝点击