最大字段和
给定有n个整数(可能为负整数)组成的序列a1,a2,…,an,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。
Input
第一行有一个正整数n(n<1000),后面跟n个整数,绝对值都小于10000。直到文件结束。
Output
输出它的最大子段和。
Sample Input
6 -2 11 -4 13 -5 -2
Sample Output
20
HINT
分别用普通O(n 3 )或O(n 2 )、分治O(nlogn)和动态规划O(n)实现。
普通
第一种方法:
#include <iostream>
using namespace std;
int main()
{
int i,j,k;
int n,s[1000],maxs=0,sum;
cin>>n;
for(i=0; i<n; i++)
cin>>s[i];
for(i=0; i<n; i++)
for(j=i; j<n; j++)
{
sum=0;
for(k=i; k<=j; k++)
sum=sum+s[k];
if(sum>maxs)
maxs=sum;
}
cout<<maxs;
return 0;
}
第二种方法:
#include <iostream>
using namespace std;
int main()
{
int i,j,k;
int n,s[1000],max=0,sum;
cin>>n;
for(i=0; i<n; i++)
cin>>s[i];
for(i=0; i<n; i++)
{
sum=0;
for(j=i; j<n; j++)
{
sum=sum+s[j];
if(sum>max)
max=sum;
}
}
cout<<max;
return 0;
}
分治法:① 将一个规模为n的问题分解为k个规模较小的子问题,子问题相互独立与原问题相同;② 如果子问题的规模小到可以直接求解则解决,否则继续分解; ③ 将各个子问题的解合并得到原问题的解。
#include <iostream>
using namespace std;
#include <math.h>
int maxsum(int s[],int left,int right)
{
int mid;
int d1,d2;
if(left==right)
return s[left];
else
{
mid=(left+right)/2;
d1=maxsum(s,left,mid);
d2=maxsum(s,mid+1,right);
int max1=0;
int sum1=0;
for(int i=mid; i>=left; i--)
{
sum1=sum1+s[i];
if(max1<sum1)
max1=sum1;
}
int max2=0;
int sum2=0;
for(int i=mid+1;i<=right;i++)
{
sum2=sum2+s[i];
if(sum2>max2)
max2=sum2;
}
int d3;
d3=max1+max2;
if(d3>d1)
d1=d3;
if(d3>d2)
d2=d3;
if(d1>d2)
return d1;
if(d2>d1)
return d2;
if(d1==d2)
return d3;
}
}
int main()
{
int n,s[1000],maxs;
cin>>n;
for(int i=0; i<n; i++)
cin>>s[i];
maxs=maxsum(s,0,n-1);
cout<<maxs;
return 0;
}
#include <iostream>
#define ll long long
using namespace std;
int main()
{
int n,i,k=0;
ll a[1001],sum=0,sums=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
if(a[i]<0)
k++;
}
if(k==n)
cout<<"0"<<endl;
else
{
for(i=0;i<n;i++)
{
if(sum>=0)
sum+=a[i];
else
sum=0+a[i];
if(sum>sums)
sums=sum;
}
cout<<sums<<endl;
}
return 0;
}