算法设计与分析不定期更新的日常之最大子段和四种方法:
代码实现如下:
#include <iostream>
#include <cstdio>///最大子段和四种方法
#include <cstring>
using namespace std;
const int maxn=100;
int maxsum1(int n,int a[],int &besti,int &bestj)///超级无敌大暴力,复杂度O(n^3)
{
int maxx=0;
for(int i=0; i<n; i++)
{
for(int j=i; j<n; j++)
{
int tmp=0;
for(int k=i; k<=j; k++)
{
tmp+=a[k];
}
if(tmp>maxx)
{
maxx=tmp;
besti=i;
bestj=j;
}
}
}
return maxx;
}
int maxsum2(int n,int a[],int &besti,int &bestj)///暴力,复杂度O(n^2)
{
int maxx=0;
for(int i=0; i<=n; i++)
{
int tmp=0;
for(int j=i; j<n; j++)
{
tmp+=a[j];
if(tmp>maxx)
{
maxx=tmp;
besti=i;
bestj=j;
}
}
}
return maxx;
}
int maxsum3(int a[],int left,int right,int &besti,int &bestj)///利用分治的方法来求解数组的最大子段和问题,时间复杂度降为O(nlogn)
{
if(left==right)
{
if(a[left]>0)
{
return a[left];
besti=bestj=left;
}
else
{
return 0;
}
}
else
{
int sum;
int mid=(left+right)/2;
int besti1,bestj1,besti2,bestj2;
besti1=bestj1=besti2=bestj2=0;
int max1=maxsum3(a,left,mid,besti1,bestj1);
int max2=maxsum3(a,mid+1,right,besti2,bestj2);
int s1,s2,tmp;
s1=s2=tmp=0;
for(int i=mid; i>=left; i--)
{
tmp+=a[i];
if(tmp>s1)
{
s1=tmp;
besti=i;
}
}
tmp=0;
for(int j=mid+1; j<=right; j++)
{
tmp+=a[j];
if(tmp>s2)
{
s2=tmp;
bestj=j;
}
}
sum=s1+s2;
if(max1>sum)
{
sum=max1;
besti=besti1;
bestj=bestj1;
}
else if(max2>sum)
{
sum=max2;
besti=besti2;
bestj=bestj2;
}
// cout<<"besti="<<besti<<" bestj="<<bestj<<endl;
return sum;
}
}
int maxsum4(int a[],int n,int *c,int &d)///利用动态规划的方法来求解最大子段和,复杂度会更低,变为O(n)
{
int b[100];
memset(b,0,sizeof(b));
b[-1]=0;
int sum=0;///采用利用c[]数组和最大子段和的最右边界d返回最大子段和下标的方法(同样可以利用b[]数组可以返回)
for(int i=0;i<n;i++)
{
if(b[i-1]>0)
{
b[i]=b[i-1]+a[i];
c[i]=1;
}
else
{
b[i]=a[i];
c[i]=2;
}
if(b[i]>sum)
{
sum=b[i];
d=i;
}
//cout<<"sum="<<sum<<endl;
}
return sum;
}
void output1(int a[],int d,int c[])///正序输出
{
int k=0;
for(int i=d;i>=0;i--)
{
if(c[i]==2)
{
k=i;
break;
}
}
for(int i=k;i<=d;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
void output2(int a[],int d,int c[])///逆序输出
{
int i=d;
do
{
printf("%d ",a[i]);
}while(c[i--]==1);
printf("\n");
}
int main()
{
int a[maxn];
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
cout<<"方法1:暴力O(n^3)"<<endl;
int bi1,bj1;
bi1=bj1=0;
int k1=maxsum1(n,a,bi1,bj1);
printf("数组中的最大子段和为%d,满足最大子段和的子段是从数组中第%d个元素开始,到%d个元素结束的.\n",k1,bi1+1,bj1+1);
cout<<"方法2:暴力O(n^2)"<<endl;
bi1=bj1=0;
int k2=maxsum2(n,a,bi1,bj1);
printf("数组中的最大子段和为%d,满足最大子段和的子段是从数组中第%d个元素开始,到%d个元素结束的.\n",k2,bi1+1,bj1+1);
cout<<"方法3:分治法O(nlog(n))"<<endl;
bi1=bj1=0;
int k3=maxsum3(a,0,n-1,bi1,bj1);
printf("数组中的最大子段和为%d,满足最大子段和的子段是从数组中第%d个元素开始,到%d个元素结束的.\n",k3,bi1+1,bj1+1);
cout<<"方法4:动态规划 "<<endl;
bi1=bj1=0;
int c[maxn];
int d;
int k4=maxsum4(a,n,c,d);
printf("数组中的最大子段和为%d.\n",k4);
cout<<"正序输出最大子段和序列:"<<endl;
output1(a,d,c);
cout<<"逆序输出最大子段和序列:"<<endl;
output2(a,d,c);
}
return 0;
}