一、题目描述:
给定一个序列a[1],a[2],a[3]…a[n],你的工作是计算子序列的最大和。例如,给定(6,-1,5,4,-7),这个序列中的最大和是6 +(-1)+ 5 + 4 = 14。
输入
输入的第一行包含一个整数T(1<=T<=20),这意味着测试用例的数量。然后T行,每一行以一个数字N(1<=N<=100000)开始,然后N个整数(所有整数都在-1000到1000之间)。
输出
对于每个测试用例,您应该输出两行。第一行是“Case #:”,#表示测试用例的编号。第二行包含三个整数,序列中的最大和、子序列的起始位置、子序列的结束位置。如果有多个结果,则输出第一个结果。在两个案例之间输出一个空行。
二、输入输出样例:
Sample Input:
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5
Sample Output:
Case 1:
14 1 4
Case 2:
7 1 6
三、实现代码:
#include <iostream>
using namespace std;
int main()
{
int a[100005]={0};
int n,j,i,k;
int p,q,x,y;
int fact,sum;
int num=1;
cin>>k;
int count=k;
for(j=0;j<k;j++)
{
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
sum=a[0];
fact=a[0];
x=0,y=0,p=0,q=0;
for(i=1;i<n;i++)
{
if(sum+a[i]<a[i])
{
sum=a[i];
x=i;
y=i;
}
else
{
sum=a[i]+sum;
y++;
}
if(sum>fact)
{
fact=sum;
p=x;
q=y;
}
}
printf("Case %d:\n",num);
printf("%d %d %d\n",fact,p+1,q+1);
if(j!=k-1)
{
printf("\n");
}
num++;
}
}
四、做题思路:
这道题和之前做过的那道利润题思路基本一致,要找到连续区间的和的最大值,并且找到该区间的起点和终点。所以:我们从第一个位置开始,让起点和终点都为这个位置,然后判断下一个位置应不应该连续上,如果能连续上,让终点向后移动一位,如果不能连续上,就让下一个位置为新的起点和终点,以此类推,遍历完整个数组。那么,本题的关键就在于如何判断应不应该连续上。
五、代码讲解:
int a[100005]={0};
int n,j,i,k;
int p,q,x,y;
int fact,sum;
int num=1;
这部分代码是本题用到的变量,fact用来记录最后的最大的和,而sum是中间所用到的和。
for(j=0;j<k;j++)
{
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
printf("Case %d:\n",num);
printf("%d %d %d\n",fact,p+1,q+1);
if(j!=k-1)
{
printf("\n");
}
num++;
}
由于本题是多组数据的输入,所以以上代码进行本道题的输入与输出。
sum=a[0];
fact=a[0];
x=0,y=0,p=0,q=0;
for(i=1;i<n;i++)
{
if(sum+a[i]<a[i])
{
sum=a[i];
x=i;
y=i;
}
else
{
sum=a[i]+sum;
y++;
}
if(sum>fact)
{
fact=sum;
p=x;
q=y;
}
}
以上为本题的核心代码,(sum+a[i]<a[i])为核心判断条件,判断下一个要不要继续往下走。 如果行(sum=sum+a[i]),如果不行(sum=a[i])。每次再取sum与fact之间的最大值,最后得到的fact即为最大的和。如果一直能连续,那么起点不变,终点一直往后移,如果中间断开了,那么将起点和终点都为此位置,然后再往后找,每一次都记录起点与终点的位置,最后得到的p与q就是最后对应最大fact的起点与终点位置。