競賽篇-----最大連續和問題

1)首先最簡單的就是模擬時間複雜度是O(n^3)

/*
最大連續和問題
O(n^3)
*/
#include<cstdio>
#include<iostream>
using namespace std;
int main() {
	int a[1005],n,sum,ans;
	while(~scanf("%d",&n)) {
		for(int i=1; i<=n; i++)
			scanf("%d",&a[i]);
		ans=a[1];
		int cnt=0;
		for(int i=1; i<=n; i++)
			for(int j=i; j<=n; j++) {
				sum=0;
				for(int k=i; k<=j; k++)					
				{
					sum+=a[k];
					cnt++;
				} 
				ans=max(ans,sum);
			}
		printf("ans=%d cnt=%d\n",ans,cnt);
	}
}

2)將上述的代碼優化一點點,運用樹狀數組的思想求子序列的和爲兩個前綴和之差

        時間複雜度爲O(n^2)相對於上面的3次方的時間複雜度優化了不少。

/*
最大連續和,運用:子序列和等於兩個前綴和之差
O(n^2) 
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a[1005],ans,n,s[1005];
	while(~scanf("%d",&n)) {
		for(int i=1; i<=n; i++)
			scanf("%d",&a[i]);
		s[0]=0;
		ans=a[1];
		for(int i=1; i<=n; i++)
			s[i]=s[i-1]+a[i];
		for(int i=1; i<=n; i++)
			for(int j=i; j<=n; j++)
				ans=max(ans,s[j]-s[i-1]);
		printf("%d\n",ans);
	}
}

3)接下來還可以將2次方是時間複雜度再次優化,那就是用分治法。

         時間複雜度爲O(nlogn),相比較而言又優化了很多

/*
分治法求最大連續和問題
分治法的三個步驟:
1)劃分問題:把問題的實例化成子問題
2)遞歸求解:遞歸解決子問題
3)合併問題:合併子問題的解,得到原問題的解
O(nlogn)
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1005];
int maxsum(int *a,int x,int y) { //返回在數組中左閉右開[x,y)的最大連續和(空區間可表示爲[x,x))
	int v,l,r,maxs;
	if(y-x==1) return a[x];//如果只有一個元素,直接返回;
	int m=x+(y-x)/2;//第一步,劃分成[x,m),[m,y);
	//此處用x+(y-x)/2,而不用(x+y)/2,'/'總是朝0方向取整,而不是向下取整,此處的方式可以保證分界點總是靠近區間起點。
	maxs=max(maxsum(a,x,m),maxsum(a,m,y));//第二步:遞歸求解子問題
	//第三步:合併;
	v=0,l=a[m-1];//從分界點開始往左的最大連續和l;
	for(int i=m-1; i>=x; i--)
		l=max(l,v+=a[i]);
	v=0,r=a[m];//從分界點開始往右的最大連續和r;
	for(int i=m; i<y; i++)
		r=max(r,v+=a[i]);
	return max(maxs,l+r);
}
int main() {
	int n;
	while(~scanf("%d",&n)) {
		for(int i=1; i<=n; i++)
			scanf("%d",&a[i]);
		printf("%d\n",maxsum(a,1,n+1));
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章