01-复杂度2 Maximum Subsequence Sum (25分)
题目描述
给定K个整数组成的序列
N
1
,
N
2
,
.
.
.
,
N
K
{ N_{1}, N_{2}, ..., N_{K} }
N1,N2,...,NK,“连续子列”被定义为
N
i
,
N
i
+
1
,
.
.
.
,
N
j
{ N_{i}, N_{i+1}, ..., N_{j} }
Ni,Ni+1,...,Nj,其中 1≤i≤j≤K。
“最大子列和”则被定义为所有连续子列元素的和中最大者。
例如给定序列
−
2
,
11
,
−
4
,
13
,
−
5
,
−
2
{ -2, 11, -4, 13, -5, -2 }
−2,11,−4,13,−5,−2,其连续子列
11
,
−
4
,
13
{ 11, -4, 13 }
11,−4,13 有最大的和
20
20
20。
现要求你编写程序,计算给定整数序列的最大子列和,以及最大子列的第一个和最后一个数字。
输入规格:
每个输入文件包含一个测试用例。 每个案例占据两行。
第一行包含一个正整数K(≤10000)。
第二行包含K个数字,以空格分隔。
输出规格:
对于每个测试用例,在一行中输出最大和,以及最大子序列的第一个和最后一个数字。
数字必须用一个空格分隔,但行尾不能有多余的空格。
如果最大子序列不是唯一的,则输出索引i和j最小的子序列(如示例所示)。
如果所有K个数字均为负,则其最大和定义为0,并且应该输出整个序列的第一个和最后一个数字。
输入样例:
10
-10 1 2 3 4 -5 -23 3 7 -21
样本输出:
10 1 4
解法
这道题在01-复杂度1 最大子序和问题基础上增加了输出最大子列的首尾数字的要求。
思路就是在 在线处理解法的基础上:
- 定义一个左界left 右界right 初始值都为nums[0]
- 定义一个当前左界 tmpleft 当前右界tmpright 初始值都为nums[0]
- 难点可能就在怎么更新 左界和右界
- 当ThisSum>=0 说明可以连续加 则更新ThisSum 和 tempright值
- 否则说明 ThisSum为负 更新ThisSum=0 更新当前左界 templeft 和当前右界 tempright值为当前元素值
- 如果ThisSum > MaxSum 更新MaxSum 和记录 left right
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
const int maxn=10000;
vector<int> a;
int main()
{
int K;
cin >> K;
cin.get();
vector<int>v;
for(int i=0;i<K;i++)
{
int temp;
cin >> temp;
v.push_back(temp);
}
int ThisSum=0,MaxSum=INT_MIN;
int left=v[0],right=v[0];
int templeft=v[0],tempright=v[0];
for(int i=0;i<v.size();i++)
{
if(ThisSum >= 0)
{
ThisSum += v[i];
tempright = v[i];
}
else
{
ThisSum = v[i];
templeft = v[i];
tempright = v[i];
}
if(ThisSum > MaxSum)
{
MaxSum = ThisSum;
left = templeft;
right = tempright;
}
}
if(MaxSum < 0)
{
MaxSum = 0;
left = v[0];
right = v[v.size()-1];
}
cout << MaxSum <<" " <<left<<" " <<right <<endl;
return 0;
}