HUD 1003 与 1024

Problem Description

Given a sequence a[1],a[2],a[3]…a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.

Input

The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).

Output

For each test case, you should output two lines. The first line is “Case #:”, # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.

Sample Input

2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5

Sample Output

Case 1:
14 1 4

Case 2:
7 1 6

题意:求最大连续子序列的和。

思路:一开始没想着用dp做啊, 开了个循环就过了,后来回来看了下自己的代码,发现虽然不是用的dp,但还是dp 的思想呢(只不过把空间从一维缩成了常数级别)。

dp [ i ] 的意思是以数字a[i] 为结尾的最大连续子序列的和,那么状态转移方程就变成了 dp[i] = max(dp[i - 1] + a[i], a[i]);

怎么解释呢这个方程呢,如果 dp[i -1] 小于零, 即以a[i - 1]为结尾的最大连续子序列和小于零,那么以a[i] 为结尾的最大连续子序列就是a[i]。 反之则等于dp[i - 1] + a[i], 由于我们状态转移的时候只用到了上一层的状态,所以可以把空间复杂度优化为常数,时间复杂度不变。

#include <iostream>
#include <algorithm>

using namespace std;
int main()
{
    int n, z = 1; cin >> n;
    
    while(n --)
    {
        int t, res = 0, l = 1, r, ans = -1010, len = 0; cin >> t;
        
        for(int i = 1; i <= t; i ++)
        {
            len ++;
            int a; scanf("%d", &a);
            
            res += a;
            if(res > ans) 
            {
                r = i, ans = res, l = r - len + 1;
            }
            if(res < 0)  res = 0, len = 0;
        }
        
        printf("Case %d:\n%d %d %d",z ++, ans, l, r);
        
        if(n == 0) puts("");
        
        else puts("\n");
        
        
    }
    return 0;
}

这是未优化版本。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100100;

int dp[N];

int main()
{
    int n; cin >> n;
    
    int t = 1;
    while(n --)
    {
        int len; cin >> len;
        
        for(int i = 1; i <= len; i ++) scanf("%d", dp + i);
        
        int res = -1010, l = 0, r = 0, ans = 0;
        
        for(int i = 1; i <= len; i ++)
        {
            dp[i] = max(dp[i - 1] + dp[i], dp[i]);
            
            if(res < dp[i])
            {
                res = dp[i], r = i, l = r - ans;
            }
            if(dp[i] > 0) ans ++;
            
            else ans = 0;
        }
        
        printf("Case %d:\n%d %d %d\n",t ++, res ,l, r);
        //cout << res << endl;
        
        if(n) cout << "\n";
        
    }
    return 0;
}

HDU1024

题意:将一串数字求m个最大连续子序列的和, 要求这些连续子序列不能重叠。

思路:一开始做的时候, wat??? 这题目什么意思,一开始还以为用前缀和来做,看了半天也没看懂题意,看了一下题解,还是不懂,后来看了一眼这道题题目是max sum plus plus ,于是去找max sum 这道题,这才明白题意,随之而来的是一脸的懵逼??这题怎么做?? 我想到用动规,但是完全不知道怎么划分状态呢,因为我前边的max sum 就没有想到是用动规(但是实际上用的思路和动规的思想一样哎,但没有从动规的角度出发),直接过了,于是我回过头去看max sum 的动规思路,emm。。 还挺简单的(见上边代码↑)。回到这个他题,我开始有模有样的做尝试,由于我先前看过一点题解,但是没看懂,第一步状态划分很顺利,f[i][j] 表示以 a[j] 为结尾的子串,分成 i 组,那么
f [i][j] = max(f [i - 1][j - k] + 以j - k + 1 为区间开头的以 j 为区间结尾且以 a[j] 作为结尾的最大连续子序列的和 ) (i < k < j), 这时候我又开始犯难,这得三层循环好吧,铁超时,换一种思路,和第一题的想法一样,就是将 a[j] 的归属分类。
则dp[i][j]=max(dp[i][j-1],max(dp[i-1][i-1]~dp[i-1][j-1]))+a[j]。

这时候我又想起了完全背包的优化方式,f[i][j - 1] = max((f [i - 1][j - k - 1] + 后边的一坨,咦,我们是不是可以把f[i][j] 分成f [i - 1][j - 1] + a[j] 和 f[i - 1][j - k] + 后边一坨加粗字号(i < k < j - 1)。 啊哈,这不就出来了吗
f[i][j] = max( f[i - 1] [j - 1] + a[j], f[i] [j - 1] + a[j])(范围的话懒得写啦)。 这样的话一定要从前边开始遍历,由于只用到


#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1100000;

int f[N], a[N], t[N];

int main()
{
    int n, m; 
    while(cin >> m >> n)
    {
        for(int i = 1; i <= n ; i ++) scanf("%d", a + i);
        int res = -1e9;
        memset(f, 0, sizeof f);
        memset(t, 0, sizeof t);
        for(int i = 1; i <= m ; i ++)
        {
            int temp = -1e9;
            for(int j = i; j <= n ;j ++)
            {
                f[j] = max(f[j - 1] + a[j], t[j - 1] + a[j]);
                t[j - 1] = temp;
                temp = max(temp, f[j]);
                if(i == m) res = max(res, f[j]);
            }
        }
        cout << res << endl;//8 6 9 7 10
    }
    return 0;
}





发布了53 篇原创文章 · 获赞 14 · 访问量 1877

猜你喜欢

转载自blog.csdn.net/weixin_45630535/article/details/104981318
HUD