原题链接
PAT甲级 1007 Maximum Subsequence Sum
题目大意
输入一个K个数的序列,找出一个子序列,该子序列的和是所有子序列中最大的,并输出最大子序列的和、第一个数、最后一个数。如果该序列全为负数,则输出最大和为0、该序列的第一个数和最后一个数。
解题思路
在输入K个数的序列时,生成一个和序列sum,sum[i]表示该序列前i个数的和。那么子序列(下标从a到b)的和就可以表示为 sum[b]-sum[a-1] ,要使该子序列的和最大,则sum[a-1]要最小,故定义一个变量min表示在b之前的最小的sum的下标,sum[b]-sum[min] 即以b为末尾时的子序列的最大和。
定义一个max_sum存放原序列的子序列的最大和,比较 max_sum 和 sum[b]-sum[min] ,判断是否需要更新max_sum,更新时应一并更新最大子序列的头数(num[min+1])和尾数(num[end])
判断是否需要更新最小的sum的下标
如图所示,当end遍历到9时,min应该等于7,此时 sum[9]-sum[7] 就是以9为末尾的最大的子序列和,该子序列下标为从8到9。
示例代码
#include<iostream>
#include<bits/stdc++.h>
#include<string>
using namespace std;
int main(){
int K, pos;
int num[10001];//num为输入的序列(下标从1开始)
int sum[10001];//sum[i]为num序列前i个数的和
bool allNegetive = true;//序列全负标志
sum[0] = 0;
cin >> K;
for(pos=1; pos<=K; pos++){
cin >> num[pos];
if(num[pos]>=0) allNegetive = false;
sum[pos] = sum[pos-1] + num[pos];
}
int min = 0;// 下标end之前的前i个数的和最小的下标
int max_sum = -1; //最大序列的和
int left_num, right_num; //最大序列的头数和尾数
for(int end=1; end<=K; end++){
if(sum[end]-sum[min] > max_sum){//min+1到end的序列和更大,更新最大和与头数和尾数
max_sum = sum[end]-sum[min];
left_num = num[min+1];
right_num = num[end];
}
if(sum[end] < sum[min]) min = end; //当前的前end个数的序列和更小,更新序列和最小下标min
}
if(allNegetive) cout << "0 " << num[1] << " " << num[K];
else cout << max_sum << " " << left_num << " " << right_num;
return 0;
}