这道题就是一道最大子段和问题,经典dp问题,只不过它不仅要你求出最大子段和,还要求你给出最大段的起始位置与结尾位置。
最大子段和就是基于递推公式 f[j]=max(f[j-1]+a[j],a[j]),至于结尾位置我们只需要在求解f数组的过程中用一个End变量记录一下即可,若此时的f[j]最大,则令End=j,而起始位置则是在得知结尾位置之后,利用结尾位置推出起始位置,至于怎样推,我这里给出两种方法。
方法一:从End位置往前累加a数组的值,如果当前累加的总和等于最大子段和就修改Start变量的值,直到遍历到a数组的第一个元素。
方法二:根据我们对f数组的定义以及递推公式可知,f数组中位于最大子段和区间内的每个元素的值均大于等于0,因此从End位置往前遍历f数组,当遇到一个小于0的值跳出即可,Start最后保存的那个值即为最大子段和的起始位置。
本来这道题就是一道裸的最大子段和问题,没什么难度,但是我wa了许多发,后来究其原因,是因为我在定义Start,End这两个变量之后,在利用循环寻找他们之前没有给他们赋初始值,因此这道题给我的一个很大的启发是:如果我们定义了某个变量,在if语句中给他们赋值,那么我们就要小心如果他不符合判断条件那么最终他很可能就没有值了(如果之前你没有对他进行初始化的话),所以我们以后在定义变量以后,最好在某处对变量进行初始化(不一定非要在定义的时候初始化)。
下面贴代码:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <ctype.h>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define eps 1e-8
#define INF 0x7fffffff
#define PI acos(-1.0)
#define seed 31//131,1313
#define MAXV 50010
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MAXN=100000+5;
int a[MAXN];
int f[MAXN];
int main()
{
int t,n;
int j,k;
scanf("%d",&t);
k=1;
while(t--){
scanf("%d",&n);
for(j=1;j<=n;j++){
scanf("%d",&a[j]);
}
f[1]=a[1];
int maxsum=f[1];
int Start,End=1;
for(j=2;j<=n;j++){
f[j]=max(f[j-1]+a[j],a[j]);
if(f[j]>maxsum){
maxsum=f[j];
End=j;
}
}
Start=End; //一定要对Start赋初始值,否则必wa
j=End;
while(f[j]>=0&&j>0){
Start=j;
j--;
}
//int p=0;
// Start=End;
// for(j=End;j>0;j--){
p+=a[j];
if(p==maxsum) Start=j;
// }
printf("Case %d:\n",k++);
printf("%d %d %d\n",maxsum,Start,End);
if(t) printf("\n");
}
return 0;
}