思路:
问题的解可以分为两种情况:
1)解没有跨过A[n-1]到A[0],即普通的求子数组和的最大值
2)解跨过A[n-1]到A[0]
对第二种情况,只要找到从A[0]开始和最大的一段(A[0],...,A[j])(0<=j<n)以及A[n-1]结尾的和最大的一段(A[i],...,A[n-1])(0<=i<n),那么第2种情况中,和的最大值M_2为:
M_2=A[i]+...A[n-1]+A[0]+...+A[j]
如果i<=j,则
M_2=A[0]+...+A[n-1] - 子数组和为负的最小值(数组元素全为正则返回0)
否则
M_2=A[0]+...+A[j]+A[i]+...+A[n-1]
#include<stdio.h>
#include<string.h>
int num[100100];
int main(){
int n,m,i,j,s,max,min,x,y,left,right;
while(~scanf("%d",&n)){
memset(num,0,sizeof(num));
for(j=i=0;i<n;i++){
scanf("%d",&num[i]);
if(num[i]<0){
j++;
}
}
if(j==n){
printf("0\n");
}else{
max=0;
for(s=i=0;i<n;i++){
if(num[i]+s>num[i]){
s+=num[i];
}else{
s=num[i];
}
if(s>max){
max=s;
}
}//首尾不连
x=s=0;left=0;
for(i=0;i<n;i++){
s+=num[i];
if(s>x){
x=s;
left=i;
}
}//从左往右的最大值
y=s=0;right=0;
for(i=n-1;i>=0;i--){
s+=num[i];
if(s>y){
y=s;
right=i;
}
}//从右往左的最大值
min=s=0;
for(i=0;i<n;i++){
if(s<0) s+=num[i];
else s=num[i];
if(s<min) min=s;
}
//首尾相连
if(left>right){
for(s=i=0;i<n;i++){
s+=num[i];
}
s-=min;
}else{
s=x+y;
}
printf("%d\n",max>s?max:s);
}
}
return 0;
}