1007 Maximum Subsequence Sum【PAT (Advanced Level) Practice】

1007 Maximum Subsequence Sum【PAT (Advanced Level) Practice】

原题链接:预览题目详情 - 1007 Maximum Subsequence Sum (pintia.cn)

1.题目原文

Given a sequence of K K K integers { N 1 N_1 N1, N 2 N_2 N2, …, N K N_K NK }. A continuous subsequence is defined to be { N i N_i Ni, N i + 1 N_{i+1} Ni+1, …, N j N_j Nj } where 1 ≤ i ≤ j ≤ K 1 \le i \le j \le K 1ijK. 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 K K ( ≤ 10000 \le 10000 10000). The second line contains K K 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 i i and j j j (as shown by the sample case). If all the K K 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

2. 题目翻译

给定一个包含 K K K 个整数的序列 { N 1 N_1 N1, N 2 N_2 N2, …, N K N_K NK }。连续子序列被定义为 { N i N_i Ni, N i + 1 N_{i+1} Ni+1, …, N j N_j Nj },其中 1 ≤ i ≤ j ≤ K 1 \le i \le j \le K 1ijK。最大子序列是具有其元素和最大值的连续子序列。例如,对于序列 { -2, 11, -4, 13, -5, -2 },其最大子序列为 { 11, -4, 13 },其最大和为 20。

现在你需要找到最大和,以及最大子序列的第一个和最后一个数字。

输入规范:

每个输入文件包含一个测试用例。每个案例占两行。第一行包含一个正整数 K K K ≤ 10000 \le 10000 10000)。第二行包含 K K K 个数字,用空格分隔。

输出规范:

对于每个测试用例,在一行中输出最大和,以及最大子序列的第一个和最后一个数字。数字之间必须用一个空格分隔,但是行末不能有多余的空格。如果最大子序列不唯一,则输出具有最小索引 i i i j j j 的子序列(如示例案例所示)。如果所有 K K K 个数字都是负数,则其最大和定义为0,你应该输出整个序列的第一个和最后一个数字。

示例输入:

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

示例输出:

10 1 4

3.解题思路

3.1题目分析

找到给定整数序列中具有最大和的连续子序列,同时输出该子序列的起始和结束位置。如果最大和不唯一,则输出具有最小起始和结束位置的子序列。如果所有数字都为负数,则最大和被定义为0,并输出整个序列的第一个和最后一个数字。

3.2基本思路

使用贪心算法,在遍历整个序列的过程中实时更新当前连续子序列的和(ThisSum)以及最大和(MaxSum),并在发现负数和为负时重新开始计算当前子序列的和。这种贪心策略使得算法在一次线性扫描中就能够找到最大和连续子序列,具有较高的效率。

3.3详解步骤

这个程序使用了贪心算法来解决最大和连续子序列的问题。以下是对算法的简要分析:

  1. 输入处理: 程序首先读取输入,其中包括整数K和一个整数序列。程序处理负数开头的情况,直到找到第一个非负数,以确保不会得到全负数序列。

  2. 变量初始化: 初始化了一些变量,如当前子序列的和(ThisSum)、最大和(MaxSum)、最大子序列的起始和结束位置(first、last)、以及当前子序列的起始和结束位置(thisf、thisl)。

  3. 迭代处理序列: 使用循环迭代整个序列,逐步计算当前子序列的和(ThisSum)。在每一步中,更新最大和(MaxSum)和最大子序列的起始和结束位置。如果当前和为负数,说明当前子序列不能对整体产生正贡献,因此重新开始计算当前子序列的和,并更新起始和结束位置。

  4. 输出结果: 最终输出最大和以及最大子序列的起始和结束位置。

  5. 算法复杂度: 由于只对序列进行了一次线性扫描,因此时间复杂度为O(K),其中K是序列的长度。空间复杂度较低,仅使用了常数个变量。

4.参考答案

#include <stdio.h>

int main() {
    
    
    int K, list[10000], ThisSum, MaxSum, first, last, thisf, thisl;
    int i;

    // 输入整数K
    scanf("%d", &K);
    
    // 初始化索引i
    i = 0;
    
    // 处理负数开头的情况,直到找到第一个非负数
    while (i < K) {
    
    
        scanf("%d", &list[i]);
        if (list[i] >= 0)
            break;
        else
            i++;
    }

    // 如果所有数字都为负数,则输出整个序列的第一个和最后一个数字
    if (i == K)
        printf("0 %d %d\n", list[0], list[K - 1]);
    else {
    
    
        // 初始化最大和以及当前子序列的起始和结束位置
        MaxSum = 0;
        thisf = thisl = i;
        ThisSum = first = last = list[i];

        // 更新最大和和子序列的起始和结束位置
        if (ThisSum > MaxSum)
            MaxSum = ThisSum;

        // 循环处理整个序列
        for (i = i + 1; i < K; i++) {
    
    
            scanf("%d", &list[i]);
            ThisSum += list[i];

            // 更新最大和和子序列的起始和结束位置
            if (ThisSum > MaxSum) {
    
    
                MaxSum = ThisSum;
                first = (list[thisf] < 0) ? list[thisf + 1] : list[thisf];
                thisl = i;
                last = list[thisl];
            } else if (ThisSum < 0) {
    
    
                // 如果当前和为负数,重新开始计算当前子序列的和,并更新起始和结束位置
                ThisSum = 0;
                thisf = thisl = i;
            } else {
    
    
                // 更新当前子序列的结束位置
                thisl = i;
            }
        }

        // 输出最大和以及最大子序列的起始和结束位置
        printf("%d %d %d\n", MaxSum, first, last);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40171190/article/details/134754247