zoukankan      html  css  js  c++  java
  • 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
    ", MAX);
    
        }
    
        return 0;
    }
    View Code

              

              

  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    An existing connection was forcibly closed by the remote host
    各种浏览器的兼容css
    vs输出窗口,显示build的时间
    sass
    网站设置404错误页
    List of content management systems
    css footer not displaying at the bottom of the page
    强制刷新css
    sp_executesql invalid object name
  • 原文地址:https://www.cnblogs.com/tommychok/p/5348404.html
Copyright © 2011-2022 走看看