分治策略
在分治策略中递归地求解一个问题,在每层递归中应用如下三个步骤:
分解 : 将问题划分成一些子问题,子问题的形式与原问题一样,只是规模更小。
解决 : 递归地求解子问题。如果子问题的规模足够小,则停止递归,直接求解。
合并 : 将子问题的解组合成原问题的解。
最大子数组问题
分治策略求解(nlg(n) )
low mid high
! ! !
# # # # # # # # #
A[low,high]的任何连续子数组的位置必然是下面的三种情况之一:
* 完全位于子数组 A[low,mid] 中,因此low<=i<=j<=mid;
* 完全位于子数组 A[mid+1,high]中, 因此mid<i<=j<=high;
* 跨越了中点,因此low<=i<=mid<j<=high;
所以A[low,high]的一个最大子数组所处的位置必然是三者之一,是 完全位于子数组 A[low,mid] 中,完全位于子数组 A[mid+1,high]中, 跨越了中点的所有子数组中和最大的;
我们可以递归地求解A[low.....mid]和A[mid+1....high]的最大子数组,因为这两个子问题仍是最大子数组问题,只是规模更小,因此剩下的工作就是寻找跨越中点的最大子数组,然后4
在三种情况中选取和最大的;
分治策略代码:
1 #include<iostream> 2 using namespace std; 3 const int inf=999999; 4 struct answer{ 5 int sum,left,right; 6 }; 7 answer find_max_crossing_subarray(int *a,int l,int mid,int r){ 8 int leftsum=-inf; 9 int sum=0; 10 int maxleft; 11 for(int i=mid;i>=l;i--){ 12 sum+=a[i]; 13 if(sum>leftsum){ 14 leftsum=sum; 15 maxleft=i; 16 } 17 } 18 int rightsum=-inf; 19 sum=0; 20 int maxright; 21 for(int i=mid+1;i<=r;i++){ 22 sum+=a[i]; 23 if(sum>rightsum){ 24 rightsum=sum; 25 maxright=i; 26 } 27 } 28 answer ans{leftsum+rightsum,maxleft,maxright}; 29 return ans; 30 } 31 answer find_max_subarray(int *a,int l,int r){ 32 if(l==r){ 33 answer ans{a[l],l,r}; 34 return ans; 35 }else{ 36 int mid=(l+r)/2; 37 answer ans1=find_max_subarray(a,l,mid); 38 answer ans2=find_max_subarray(a,mid+1,r); 39 answer ans3=find_max_crossing_subarray(a,l,mid,r); 40 if(ans1.sum>=ans2.sum&&ans1.sum>=ans2.sum){ 41 return ans1; 42 }else if(ans2.sum>=ans1.sum&&ans2.sum>=ans3.sum){ 43 return ans2; 44 }else{ 45 return ans3; 46 } 47 } 48 } 49 int main(){ 50 int n; 51 cin>>n; 52 int a[n]; 53 for(int i=0;i<n;i++) 54 cin>>a[i]; 55 answer ans=find_max_subarray(a,0,n-1); 56 cout<<ans.left<<" "<<ans.right<<" "<<ans.sum<<endl; 57 return 0; 58 }
当然也有线性时间的解法(O(n) )
从头遍历一遍,当sum>max时,更新指针和max; 当sum<0时,将sum归0,因为负数加上去只会让后面的数变小,故舍弃这一段,所以sum=0,更新指针t.
1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int n; 5 cin>>n; 6 int a[n]; 7 for(int i=0;i<n;i++) 8 cin>>a[i]; 9 int sum=0,max=-999999,l=0,r=0,t=0; 10 for(int i=0;i<n;i++){ 11 sum+=a[i]; 12 if(sum>max){ 13 max=sum; 14 l=t; r=i; 15 }else if(sum<0){ 16 sum=0; 17 t=i+1; 18 } 19 } 20 cout<<l<<" "<<r<<" "<<max<<endl; 21 return 0; 22 }