最大子段和問題的分治算法和動態規劃算法

如果將所給的序列a[1:n]分爲長度相等的兩段a[1:n/2]和a[n/2:n],分別求出這兩段的最大子段和,則a[1:n]的最大子段和有三種情形:(當所有整數均爲負數時定義其最大子段和爲0)

1)a[1:n]的最大子段和與a[1:n/2]的最大子段和相同;

2)a[1:n]的最大子段和與a[n/2:n]的最大子段和相同;

3)a[1:n]的最大子段和爲Σ(k=i~j)ak,且1<=i<=n/2,n/2+1<=j<=n;

(1)(2)可遞歸求得。對於(3),容易看出a[n/2]與a[n/2+1]在最優子序列中。據此可以設計出分治算法如下:

#include<iostream>
using namespace std;

int MaxSubSum(int *a,int left,int right)
{
	int i,leftsum,rightsum,lefts,rights,center,s1,s2;
	int sum=0;

	if(left==right)
		sum=a[left]>0?a[left]:0;
	else
	{
		 center=(left+right)/2;
		 leftsum=MaxSubSum(a,left,center);
		 rightsum=MaxSubSum(a,center+1,right);

		 s1=0;
		 lefts=0;
		for(i=center;i>=left;i--)
		{
			lefts+=a[i];
			if(lefts>s1)
				s1=lefts;
		}

		 s2=0;
		 rights=0;
		for(i=center+1;i<=right;i++)
		{
			rights+=a[i];
			if(rights>s2)
				s2=rights;
		}

		sum=s1+s2;
		if(sum<leftsum)
			sum=leftsum;
		if(sum<rightsum)
			sum=rightsum;
	}
	return sum;
}


int main()
{
	int a[6]={-2,11,-4,13,-5,-2};
	int s;

	s=MaxSubSum(a,0,5);
	cout<<s<<endl;

	return 0;
}

//該算法計算時間T(n)=O(nlogn)
//結果20






設b[j]爲序列a[k]從i~j的各子段和中的最大值(1<=j<=n)。有b[j-1]>0時,b[j]=b[j-1]+a[j],否則b[j]=a[j]。

所以b[j]的動態規劃式爲:b[j]=max{b[j-1]+a[j],a[j]}   (1<=j<=n)

#include<iostream>
using namespace std;

int MaxSum(int n,int *a)
{
	int sum=0,b=0;
	for(int i=0;i<=n;i++)
	{
		if(b>0)
			b+=a[i];
		else
			b=a[i];
		if(b>sum)
			sum=b;
	}
	return sum;
}


int main()
{
	int a[6]={-2,11,-4,13,-5,-2};
	int s;

	s=MaxSum(5,a);
	cout<<s<<endl;


	return 0;
}

//該算法O(n),結果20



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