算法导论 第四章:分治法(一)

来源:互联网 发布:小米电视怎么设置网络 编辑:程序博客网 时间:2024/06/05 05:09

无论是在生活中还是在计算机科学中,“分而治之”的思想占据着举足轻重的地位,其原理如下:

    1)将一个复杂的问题分成若干个相同或相似的子问题

    2)递归求解子问题,当子问题规模很小时,可直接求解

    3)将所有子问题的解合并,即为原问题的解    


1.最大子数组问题(maximum-subarray problem)

 即一段非空的,连续的有最大和的一段子数组,如:

若采用暴力求解方法,时间复杂度是Θ(n²)。这里我们用分治法求解,将数组分为两个尽可能等长的子数组,那么最大子数组A[i...j]存在三种情况:

1)完全在子数组A[low...mid]中,满足low ≤ i ≤ j ≤ mid

2)完全在子数组A[mid+1...high]中,满足 mid<i≤j≤high

3)跨越中点(midpoint),满足low ≤ i ≤ mid < j ≤ high

当为情况3时,只需要寻找形如A[i...mid]和A[mid+1...high]的最大子数组,然后连接他们。伪代码如下:


其运行时间为:O(n)。

最大子数组算法的伪代码如下:

运行时间为:

最大子数组问题也可以在线性时间内求解,具体思想参加算法导论(第三版)课后题4.1-5.


三种求解方法的完整代码如下:

#include<iostream>#include<limits.h>using namespace std;int maxSubarr_start;   //save the start index of maximum subarray with divid-and-conquer solutionint maxSubarr_end;void Bruteforce_MaxSubarr(int a[],int n,int *res){//Brute-force solutionint maxSum=INT_MIN;for(int i=0;i<n;i++)for(int j=i;j<n;j++) { int temp=0;for(int k=i;k<=j;k++)temp+=a[k];if(temp>maxSum){ maxSum=temp;res[0]=i;      //store the start index in array res[0]res[1]=j;      //store the end index in array res[1]res[2]=maxSum; //store the maxSum in array res[2]} }}int Crossing_MaxSubarr(int a[],int low,int mid,int high){//case:maximum subarray corssing mid indexint left_sum=INT_MIN;int sum=0;for(int i=mid;i>=low;i--){ sum+=a[i];if(sum>left_sum) {left_sum=sum;maxSubarr_start=i;}}int right_sum=INT_MIN;sum=0;for(int j=mid+1;j<=high;j++){sum+=a[j];if(sum>right_sum){right_sum=sum;maxSubarr_end=j;}}return left_sum+right_sum;}int DC_MaxSubarr(int a[],int low,int high){//divide-and-conquer solutionif(high==low)        //only one elementreturn a[low];//divid-and-conquer int mid=(low+high)/2;int left_sum  = DC_MaxSubarr(a,low,mid);int right_sum = DC_MaxSubarr(a,mid+1,high);int cross_sum = Crossing_MaxSubarr(a,low,mid,high);if(left_sum>right_sum && left_sum>cross_sum)return left_sum;else if(right_sum>left_sum && right_sum>cross_sum)return right_sum;elsereturn cross_sum;}void LinearTime_MaxSubarr(int a[],int low,int high,int *res){//linear time solution int temp=0;int maxSum=INT_MIN;int max_start,max_end;for(int i=low;i<=high;i++) {temp+=a[i];if(temp>maxSum)       //if a[i]<=0 ,refuse{maxSum=temp;   max_end=i;       //the end index of maximum subarray }  if(temp<0)//start at a[i+1]temp=0;}//find the start index of maximum subarraytemp=maxSum;for(int j=max_end;j>=low;j--){temp-=a[j];if(temp==0){max_start=j;break;} }//cout<<"the result:"<<max_start<<"   "<<max_end<<"   "<<maxSum<<endl;res[0]=max_start;res[1]=max_end;res[2]=maxSum;}int main(){int a[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};int n=sizeof(a)/sizeof(int);/*-------the maximum-subarray with brute-force solution as following:------*/int *result0;result0=new int[3];Bruteforce_MaxSubarr(a,n,result0);cout<<"Brute-force solution as following:"<<endl;cout<<result0[0]<<"   "<<result0[1]<<"   "<<result0[2]<<endl;/*---the maximum-subarray with divid-and-conquer solution as following:----*/int result1;cout<<"Divid-Conquer solution as following:"<<endl;result1=DC_MaxSubarr(a,0,n-1);cout<<maxSubarr_start<<"   "<<maxSubarr_end<<"   "<<result1<<endl;/*-------the maximum-subarry with linear-time solution as following:------*/int *result2;result2=new int[3];cout<<"Linear-time solution as following :"<<endl;LinearTime_MaxSubarr(a,0,n-1,result2);cout<<result2[0]<<"   "<<result2[1]<<"   "<<result2[2]<<endl;return 0;}
运行结果:


第一个数表示最大子数组的起始位置;第二个是表示终止位置;第三个数表示最大子数组和。


0 0
原创粉丝点击