HDU 1024 Max Sum Plus Plus --- dp+滚动数组

  HDU 1024

  题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交。

  解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值,其中第i个子序列包括a[j],

       则max(dp[m][k]),m<=k<=n 即为所求的结果

       <2>初始状态: dp[i][0] = 0, dp[0][j] = 0;

       <3>状态转移:

          决策:a[j]自己成为一个子段,还是接在前面一个子段的后面

          方程:

              a[j]直接接在前面的子段之后, 则dp[i][j] = dp[i][j-1] + a[j];

              a[j]自己作为一个子段,先求得前面k个数组成的最大i-1段子段和,再加上a[j],

              即dp[i][j] = max(dp[i-1][k]) + a[j],其中 1=<k<=j-1;

          即 dp[i][j] = max(dp[i][j-1] + a[j], max(dp[i-1][k]) + a[j]), 其中k>=1&&k<=j-1;

       <4>空间复杂度优化:

          本题由于n可以达到100 0000,开不出dp[n][n],因此需要利用滚动数组优化空间。

          从状态转移方程中可以看到,当前行位置为j的状态dp[i][j]的更新只需要利用到上一行的前j-1个状态最大值

          因此最多只需要两行数组

       <5>时间复杂度优化:

          每次更新dp[i][j]时,都需要找到上一行的前j-1个状态的最大值,这样复杂会达到O(n^3);

          其实,可以每次更新当前行的dp[i][j]后,将其相应的前j个数的最大值保存在pre[j]中,

          这样,在下次更新下一行时可以可以直接使用当前行保存的pre[j],而不用再搜索,

          因此,时间复杂度可以优化到O(n^2)

/* HDU 1024 Max Sum Plus Plus --- dp+滚动数组 */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 1000005;
int dp[maxn], pre[maxn];    //pre[j] = dp[i-1][
int a[maxn];
int m, n;

int main()
{
#ifdef _LOCAL
    freopen("D:\\input.txt", "r", stdin);
#endif

    while (scanf("%d%d", &m, &n) == 2){
        //输入
        for (int i = 1; i <= n; ++i){
            scanf("%d", a + i);
        }//for(i)
        int MAX;

        //定义第一行的第一个状态的前驱,此时的i相当于1,dp[1][0]
        dp[0] = 0;
        //初始化pre数组全为0,此时pre数组所对应的行应该为0,
        memset(pre, 0, sizeof pre);
        for (int i = 1; i <= m; ++i){
            //内循环做的是更新当前第i行的状态, 注意 j >= i 才有意义

            MAX = -10e8;    //将MAX初始化为一个很小的数
            for (int j = i; j <= n; ++j){
                /*
                    状态转移方程里的pre[j]保存的是上一行的前j个数的最大值,
                    即pre[j] = max(dp[i-1][k]), 1<=k<=j

                    若a[j]直接属于第i段, 则 dp[i][j] = dp[i][j-1] + a[j]
                    在这里就是 dp[j] = dp[j-1]+a[j]
                    若a[j]自成一段,则需要找出 dp[i-1][k]的最大值,其中 1<=k<=j-1,即pre[j-1]
                */

                dp[j] = max(dp[j - 1], pre[j - 1]) + a[j];
                /*
                    下面pre数组和上面有细微的区别
                    上面的pre[j-1]保存是上一行(第i-1行)的前j-1个数的最小值
                    而下面的pre[j-1]更新后保存的是当前行的前j-1个数的最大值,
                    更新后是用于下一行的dp的更新,即i要+1后才会用到
                    另注意MAX是上次内循环所更新的值,即当前行(i)的前j-1个数的最大值
                */
                pre[j - 1] = MAX;//更新pre,保存当前行的前j-1个数的最大值,为下一行的dp更新做准备
                if (dp[j] > MAX){
                    //这里的MAX记录的是当前行的前j位的最大值
                    //到下一个内循环j会+1,这就是为什么MAX可以在上面用于更新pre[j-1]
                    MAX = dp[j];    //MAX记录当前行的前j位的最大值
                }
            }
        }//for(i)
        printf("%d\n", MAX);

    }

    return 0;
}

          

          

时间: 2024-08-02 02:50:27

HDU 1024 Max Sum Plus Plus --- dp+滚动数组的相关文章

HDU 1024 Max Sum Plus Plus (DP&#183;滚动数组)

题意  从n个数的数组中选出不相交的m段  求被选数的和的最大值 Max Sum 的升级版  不只是要选一段连续的了  而是选m段  思想还是类似  依旧dp 状态和状态转移方程不是很难想  在 Max Sum 这个问题中 dp[i] 表示的是以第i个数结尾的一段的 Max Sum  由于这里还有一个多少段的状态  于是这里令 dp[i][j] 表示在前 i 个数中选取 j 组  且第 i 个数在最后一组中的 Max Sum Plus Plus 那么现在对于第i个数有两种决策 1,  第 i 个

HDU - 1024 Max Sum Plus Plus(dp+滚动数组优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 题意:给定n个数字,求其中m段的最大值(段与段之间不用连续,但是一段中要连续) 例如:2 5 1 -2 2 3 -1五个数字中选2个,选择1和2 3这两段. 题解:dp[i][j]从前j个数字中选择i段,然后根据第j个数字是否独立成一段,可以写出 状态转移方程:dp[i][j]=max(dp[i][j-1]+num[j],max(dp[i-1][k])+num[j]) 这里的max(dp[i-

HDU 1024 Max Sum Plus Plus Dp题解

本题就是求m段子段,而且要求这些子段加起来和最大,最大子段和的Plus版本. 不过题意真的不好理解,x,y什么的都没有说清楚. 知道题意就开始解题了,这肯定是动态规划法了. 动态规划法的程序不难写,关键是抽象思维. 这里的最小情况是只分成一段的时候,就退化为最大子段和问题了,这个是段数的最小情况了: 如果只有0个数的时候,结果肯定为零了,或者如果只有一个数的时候就是这个数了,那么数列只有0个或者1个的时候就是数组的最小情况了. 然后记录使用一个数组记录dp[MAX_N],其中dp[i]的含义就是

Hdu 1024 Max Sum Plus Plus (dp)

题目链接: Hdu 1024 Max Sum Plus Plus 题目描述: 给出n个数,问m段连续子序列的和相加最大是多少? 解题思路: dp[i][j]表示把前i个元素(包括第i个),分成j段的最大和.状态转移方程就是dp[i][j] = max (dp[i-1][j] + arr[j],  max( dp[k][j-1]) + arr[j]),其中0<k<i.(第i个元素是保存在第j段,还是自己单独成段) 由于1<=n<=1000,000.n*n的数组肯定会爆炸,所以要对方程

hdu 1024 Max Sum Plus Plus(DP&amp;最大连续和加强版)

Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 16843    Accepted Submission(s): 5539 Problem Description Now I think you have got an AC in Ignatius.L's "Max Sum" problem

HDU 1024 Max Sum Plus Plus(二维数组转化为一维数组)

Problem Description: Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem. Given a consecutive number seq

hdu 1024 Max Sum Plus Plus(DP)

转移方程dp[i][j]=Max(dp[i][j-1]+a[j],max(dp[i-1][k] ) + a[j] ) 0<k<j 此链接中有详解点击打开链接 #include<stdio.h> #include<algorithm> #include<iostream> using namespace std; #define MAXN 1000000 #define INF 0x7fffffff int dp[MAXN+10]; int mmax[MAXN

[2016-03-28][HDU][1024][Max Sum Plus Plus]

时间:2016-03-28 17:45:33 星期一 题目编号:[2016-03-28][HDU][1024][Max Sum Plus Plus] 题目大意:从n个数字提取出一定数字组成m个部分,使得这个部分的总和最大 分析: dp[i][j]表示前i段计算第j个数字,dp[i][j] = max(dp[i - 1][j - 1] + a[j],dp[i][k] + a[j]); #include <algorithm> #include <cstring> #include &

HDU 1024 Max Sum Plus Plus

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21926    Accepted Submission(s): 7342 Problem Description Now I think you ha