http://acm.hdu.edu.cn/showproblem.php?pid=1003
题目大意:输入T为总的案例数,每个案例中首先输入N表示数组长度,随后输入N个数a[1]-a[N]表示一个数组,求一个子数组,要求这个子数组所有数加起来和最大,并输出这个子数组的起始下标,如果有多个子数组都是和最大的,则输出第一个满足条件的子数组的下标。
考虑前N个元素(数组所有元素),设f[N]为从前N个元素选择,最大子数组的和。则求前N个元素的最大子数组,有两种情况:1、最大子数组不包含a[N],此时前N个元素的最大子数组为前N-1个元素的最大子数组f[N-1]。2、最大子数组以a[N]结尾,设g[N]表示以a[N]结尾的最大子数组的和。以a[N]结尾最大子数组,要么是a[N]自己本身,要么是以a[N-1]结尾的最大子数组,要么是a[N]自己,所以确立递推关系g[N]=max{ a[N],g[N-1]+a[N] }。总的递推关系:f[N]=max{ g[N] , f[N-1] }。
这里还有一个问题,需要输出最大子数组的起始下标,我们引入了两组变量:tmpstart、tmpend和preleft、preright,两组变量的定义已经写在了注释当中。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
//#define DEBUG
void solve(int *left,int *right);
int T;
int N;
int a[100005];
int f[100005],g[100005];
int main(){
cin>>T;
int left,right;
for(int i=1;i<=T;i++){
cin>>N;
for(int j=1;j<=N;j++) cin>>a[j];//a[1]-a[N]为待求序列
solve(&left,&right);
cout<<"Case "<<i<<":"<<endl;
cout<<f[N]<<" "<<left<<" "<<right<<endl;
if(i!=T) cout<<endl;
}
}
void solve(int *left,int *right){
int start,end;
f[1]=a[1];
g[1]=a[1];
int tmpstart=1,tmpend=1;//求前i个元素的最大子数组的时候以第i个数字结尾的最大子序列左右两个下标
int preleft=1,preright=1;//当求前i个数字的最大子数组的时候,这组变量表示前i-1个元素的最大子数组的两个下标
for(int i=2;i<=N;i++){
if(g[i-1]+a[i]>=a[i]){//当有多个子序列满足条件的时候输出第一个子序列的起止下标,所以这里有等号,这个等号是我通过实际的测试数据测试过后加上的
tmpend=i;
g[i]=g[i-1]+a[i];
}else{
tmpstart=tmpend=i;
g[i]=a[i];
}
if(f[i-1]>=g[i]){
f[i]=f[i-1];
*left=preleft;
*right=preright;
}else{
f[i]=g[i];
*left=tmpstart;
*right=tmpend;
}
//此时*left,*right为前i个元素最大子序列的起止下标
#ifdef DEBUG
cout<<"i="<<i<<endl;
cout<<"f["<<i-1<<"]="<<f[i-1]<<endl;
cout<<"g["<<i<<"]="<<g[i]<<endl;
cout<<"f["<<i<<"]="<<f[i]<<endl;
cout<<"left="<<(*left)<<"right="<<(*right)<<endl;
#endif
preleft=*left;
preright=*right;
}
}