hdu1024(dp)

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

 

题意:给出一个有n个元素的数组,从其中选出m个不相交区间,求m个区间所有数字和最大为多少

 

思路:很明显dp

我们可以用dp[i][j]存储前i个区间前j个元素和的最大值,最终答案为dp[n][m];

假设当前为第i个区间,对于第j个元素,我们可以将其加入前i个区间,或者将其单独作为一个区间;

那么状态转移方程为:

dp[i][j]=max(dp[i][j-1]+a[j], max(dp[i-1][k])+a[j])  //如果我们将第j个元素加入前i个区间,那么有dp[i][j]=dp[i][j-1]+a[j],

如果将其单独作为一个区间,那么dp[i][j]=前i-1个区间最大值+a[j],即为dp[i][j]=max(dp[i-1][k])+a[j] (1<=k<=n),max(dp[i-1][k]表示前i-1个区间前j个元素能得到的最大值,那么为了得到分成i-1个区间能得到的最大值我们需要遍历一下k;

时间复杂度为 O(m*n^2)

 

本题的数据范围为1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767,  m没有给出范围,也很显然我们上面的算法会超时 ,仔细分析一下我们可以发现max(dp[i-1][k])的值我们在之前已经计算过了,我们只需要开一个一维数组来保持前i-1个区间能得到的最大值即可;

前面的算法还有一个bug就是如果m稍大一点的话开二维数组会爆内存的,因此,我们需要将其优化成一维数组,用vis[i]表示前i-1个区间能得到的最大和;

dp[i][j]中的i可以有外面的for循环控制,那么我们用dp[j]代替前面的dp[i][j]即可;

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <math.h>
 5 #include <algorithm>
 6 #define MAXN 1000010
 7 #define INF 999999999
 8 using namespace std;
 9 
10 int vis[MAXN], a[MAXN], dp[MAXN];
11 
12 int main(void){
13     int m, n, mx;
14     while(~scanf("%d%d", &m, &n)){
15         memset(vis, 0, sizeof(vis));
16         memset(dp, 0, sizeof(dp));
17         for(int i=1; i<=n; i++){
18             scanf("%d", &a[i]);
19         }
20         for(int i=1; i<=m; i++){
21             mx=-1*INF;
22             for(int j=i; j<=n; j++){ //注意这里j是从i开始,因为前面已经分了i-1个区间,至少用了i-1个元素嘛
23                 dp[j]=max(dp[j-1]+a[j], vis[j-1]+a[j]);
24                 vis[j-1]=mx;
25                 if(mx<dp[j]){
26                     mx=dp[j];
27                 }
28             }
29         }
30         printf("%d\n", mx);
31     }
32     return 0;
33 }

 

posted @ 2016-11-26 21:08  geloutingyu  阅读(155)  评论(0编辑  收藏  举报