问题描述
大意:
给定一个序列a[1],a[2],a[3]…a[n],你需要算出其子序列中的最大值。比如说:给你一个序列(6,-1,5,4,-7),它的子序列之和中的最大值是6 + (-1) + 5 + 4 = 14。
输入
大意:
第一行是一个范围在1到20的整数T,代表着接下来输入的测试案例;
接下来的T行,每一行都首先是一个范围在1到100000的数字N,代表着该测试案例中所包含的测试数据个数。其次,接着就是N个范围在-1000到1000的测试数据。
输出
大意:
对于每一个测试案例结果,输出两行。
第一行是 “Case #:”,#代表着测试案例的序号;
第二行是三个数据,分别是最大子序列之和、子序列在原序列中的起始位下标加一和末位下标加一;
如果测试案例不止一个,输出测试案例结果之间需要有一个空行。
算法思想:
这道题用到的算法思想是动态规划,鉴于该题是入门级的动态规划题,我就简单讲一下我对动态规划的基础认识。
比如说,1+1+1+1+1=5,那么再加1呢,等于6。可以发现,我们非常快地得出了答案,那是因为我们记住了上一个结果是5,5+1=6。如果我们重新1+1+1+1+1+1=6,那么肯定会慢,而且会造成许多不必要的浪费。
于是为了解决冗余,我们把从一开始逐步得出的结果记录下来,直到最终得到答案。所以总的来说,这是一个牺牲空间换取时间的算法
解题思路:
在输入数据同时,数据加到序列和里,边加边比较。最大值小于序列和时,最大值更新,记录起始位,末位数更新为现位。若序列和小于0时,序列和置0,起始位更新为下一位。
#include<iostream>
using namespace std;
int a[100000];
void solve(int k, int n, int t)//动态规划
{
int sum = 0, max_num = -1000, end_tag, start_tag = 1, temp = 1;//因为所有整数都在-1000到1000之间,所以max_num最小值为-1000
for (int i = 0; i < n; i++)
{
sum += a[i];
if (sum > max_num)//后面的和>前面的和的情况
{
max_num = sum;
start_tag = temp;//这里是子序列的开始,需要变换,与i无关
end_tag = i + 1;//这里是子序列的结束,无需变换,只与i有关
}
if (sum < 0)//这个地方是最为关键的地方
{
temp = i + 2;//序列和置0,起始位更新为下一位。
sum = 0;
}
}
cout << "Case " << k << ":" << endl;
if (k != t)
cout << max_num << " " << start_tag << " " << end_tag << endl << endl;
else
cout << max_num << " " << start_tag << " " << end_tag << endl;
}
int main()
{
int t, n;
cin >> t;
for (int i = 1; i <= t; i++)
{
cin >> n;//这个是自己错的地方,以为这里也是数列的一部分
for (int j = 0; j < n; j++)
cin >> a[j];
solve(i, n, t);
}
return 0;
}