A1007 Maximum Subsequence Sum (25 分)(最大连续子序列和)(DP问题)

Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to be { N​i​​, N​i+1​​, ..., N​j​​ } where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:

10 1 4

题意:

给一个数字序列a1, a2, a3,...,an,求i,j (1<= i <= j <= n),使得ai+...+aj 最大,输出最大和以及ai, aj. 如果有多种方案,那么输出其中i, j最小的一组。如果所有数都小于0,那么认为最大和为0,并输出首尾元素

思路:

典型的DP问题

dp[i] 存放以a[i]为结尾的连续序列最大和, s[i] 存放dp[i] 取得最大序列和时的a从哪一个元素开始。

  1. 最大和时本身:dp[i] = a[i], s[i] = i
  2. 最大和有多个元素为:dp[i - 1] + a[i], s[i] = s[i - 1]

难点在于 s[i] 的建立

所有数小于0的情况应该先处理,并无难度,只是增加判断

注意:

  1. 题目要求输出i, j 最小的方案,因此在计算时,第二种情况的优先级更高,而且最后dp[i] > MAX 时才更新k,而不是dp[i] >= MAX 
#include <cstdio>
const int maxn = 10010;
int a[maxn], dp[maxn];
int s[maxn] = {0};
int main(){
    int n;
    scanf("%d", &n);
    bool flag = false;      //表示数组中是否全小于0
    for(int i = 0; i < n; i++){
        scanf("%d", &a[i]);
        if(a[i] >= 0)
            flag = true;
    }
    if(flag == false){
        printf("0 %d %d\n", a[0], a[n - 1]);
        return 0;
    }
    //边界
    dp[0] = a[0];
    for(int i = 1; i < n; i++){
        //状态转移方程
        if(dp[i - 1] + a[i] > a[i]){
            dp[i] = dp[i - 1] + a[i];
            s[i] = s[i - 1];
        }
        else{
            dp[i] = a[i];
            s[i] = i;
        }
    }
    int k = 0;
    for(int i = 1; i < n; i++){
        if(dp[i] > dp[k]){
            k = i;
        }
    }
    //注意s[k]存放的是下标,a[s[k]]是取出第一个元素
    printf("%d %d %d\n", dp[k], a[s[k]], a[k]);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值