zoukankan      html  css  js  c++  java
  • 杭电1024Max Sum Plus Plus

     地址:http://acm.hdu.edu.cn/showproblem.php?pid=1024

    题目:

    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 sequence S1, S2, S3, S4 ... Sx, ... Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function sum(i, j) = Si + ... + Sj (1 ≤ i ≤ j ≤ n).

    Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + ... + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).

    But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead. ^_^
     
    Input
    Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 ... Sn.
    Process to the end of file.
     
    Output
    Output the maximal summation described above in one line.
     
    Sample Input
    1 3 1 2 3 2 6 -1 4 -2 3 -2 3
     
    Sample Output
    6 8
    Hint
    Huge input, scanf and dynamic programming is recommended.
     
     
    一开始,题目都没看懂,(os:题目讲的什么鬼,英语差就是心酸= =)
    后来看懂了题目意思后也没做出来,没想到那种dp方法,好心累,估计是dp题做得少的原因吧。。
    之后看了看了几个人的博客,才会的,原地址http://blog.csdn.net/lishuhuakai/article/details/8067474
    还有一个的忘了。。。
    先讲下题目意思吧:先讲下连续最大子段和,就是给你n个数,a[1]....1[n],求a[i]+.a[i+1]...+a[j]的最大值。
        此时状态转移方程:dp[i]=a[i]+(dp[i-1]>0?dp[i-1]:0)(dp【i】代表选了a【i】时的最大子段和)
           呃,不知道怎么表达了,上图吧:
        
    dp[i]a[i] 2 -1 3 -8 9
    1 2        
    2   1      
    3     4    
    4       -4  
    5         9
        对于连续最大和,只需要扫描一遍数组就好了
        1024题呢,就是把n个数分成x(x∈[m,n])段后,求这其中m个的子段和(不相交)的最大值;  
        由连续最大子段和的解法可以推广到求m个最大字段和,
                 dp[i][j] = max(dp[i][j-1],max(dp[i-1][k]))+a[j];(i-1<=k<=j-1)
        其中dp【i】【j】时,前j个元素中取i个子段的最大和(一定取了a【j】)
        所以由dp[i][j-1]到dp[i][j] 时,有两种取法:
        1:a[j]和前一个以a[j-1]的子段合并
        2:独立成一个子段;
          以题目的第二组数据为例:
        
    dp ij) -1 4 -2 3 -2 3
    1 -1 4 2 5 3 6
    2 3 2 7 5 8
    3 1 6 5 10
    4 4 4 9
    5 2 7
        
     
     
     
     
    maxtemp
    1 -1 4 4 5 5
    2 3 3 7 7
    3 1 6 6
    4 4 9
    5 2
       
     
     
     
     
     
       
    没写的代表不用算。。。
        这样dp方程就有了,不过因为题目所给的数据较大,1 ≤ n ≤ 1,000,000,
        空间复杂度:m*n,很容易就超了
        时间复杂度:n^3,也是会超的
        所以继续优化,容易看出,每次使用dp方程时,其实只涉及到两个数组dp[i][k]和dp[i-1][k],所以可以化简为两个数组dp1[i],dp2[i]储存。
        这样空间复杂度就降低到m了
        然而时间复杂度没变,继续优化,我们可以用另一个数组maxtemp[i]来储存max(dp[i-1][k])(i-1<=k<=j-1),
        所以dp方程变为:
            dp[i][j] = max(dp[i][j-1],maxtemp[i-1])+a[j];
        这样时间复杂度就变成n^2了,可以接受了。
        其实,空间还可以优化,用一个dp数组就可以了,因为dp[i]从左向右递推时,只和dp[i-1],maxtemp[i-1]有关,
        所以可以删去dp2[i].
        上代码:
     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <cstring>
     6 #include <queue>
     7 #include <stack>
     8 #include <map>
     9 #include <vector>
    10 
    11 #define N 1000010
    12 #define PI acos((double)-1)
    13 #define E exp(double(1))
    14 using namespace std;
    15 int dp1[N];
    16 int maxtemp[N];
    17 int a[N];
    18 
    19 int main(void)
    20 {
    21     int n, m, max1;
    22     while (scanf("%d%d", &m, &n) == 2)
    23     {
    24         for (int i = 1; i <= n; i++)
    25             scanf("%d", &a[i]);
    26         dp1[1] = maxtemp[1] = max1 = a[1];
    27         for (int i = 2; i <= n; i++)
    28         {
    29             if (max1 >= 0)
    30             {
    31                 dp1[i] =  a[i] + max1;
    32                 max1 += a[i];
    33             }
    34             else
    35             {
    36                 dp1[i] = a[i];
    37                 max1 = a[i];
    38             }
    39         }
    40         for (int i = 2; i <= m; i++)
    41         {
    42             maxtemp[i-1] = dp1[i-1];
    43             for (int j = i ; j < n; j++)
    44             {
    45                 if (maxtemp[j - 1]<dp1[j])
    46                 {
    47                     maxtemp[j] = dp1[j];
    48                 }
    49                 else
    50                     maxtemp[j] = maxtemp[j - 1];
    51             }
    52             for (int j = i; j <= n; j++)
    53             {
    54                 if (i == j)
    55                     dp1[j] = maxtemp[j - 1] + a[j];
    56                 else
    57                     dp1[j] = max(dp1[j - 1], maxtemp[j - 1]) + a[j];
    58             }
    59         }
    60         max1 = dp1[m];
    61         for (int i = m; i <= n; i++)
    62             if (max1<dp1[i])
    63                 max1 = dp1[i];
    64         cout << max1 << endl;
    65 
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    用户需求调研报告
    返回一个二维数组中的最大联通子数组(补)
    代码大全读后感(3)
    代码大全读后感(2)
    返回一个二维整数数组中最大联通子数组的和
    冲刺第一阶段总结
    大道至简读书笔记三
    大道至简读书笔记二
    大道至简读书笔记一
    软件工程课程改进意见
  • 原文地址:https://www.cnblogs.com/weeping/p/5361145.html
Copyright © 2011-2022 走看看