分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。
步骤:
1,划分问题:把问题的实力划分成子问题
2,递归求解:递归解决子问题。
3. 合并问题:合并子问题的解得到原问题的解。
下面介绍一个例子。(帮助理解分治法)
求最大连续和,给出一个长度为n的序列A1,A2,...An,求最大连续和。换句话说,要求找到1<=i<=j<=n,使得Ai+Ai+1+...+Aj最大
分析:
在本例中,“划分”就是把序列分成元素个数尽量相等的两半,“递归求解”就是分别求出完全位于左半或者右半的最佳序列;“合并”就是求出起点位于左半、终点位于右半的最大连续子序列的和,并和子问题的最优解比较。
前两部分没有什么特别之处,关键在于“合并”步骤。既然起点位于左半,终点位于右半,则可以人为地把这样的序列分成两部分,然后独立求解,先寻找最佳起点,然后再寻找最佳终点。
代码如下:
<span style="font-size:24px;">#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#include"algorithm"
#include"math.h"
using namespace std;
//求最大连续和
//时间复杂度 O(nlogn)
long long maxsum(int a[],int x,int y) //返回闭合区间【x,y】中最大的连续和
{
if(x==y) return a[x]; //只有一个元素直接返回
//int m=(x+y)/2;
int m=x+(y-x)/2;
//相比上一句,这样写更具有鲁棒性。
//分治的第一步,划分成【x,m】和【m+1,y】 两部分
long long sum_max=max(maxsum(a,x,m),maxsum(a,m+1,y));
//分治法的第二步,递归求解(子问题的最优解)
long long L_sum=0,R_sum=0,tem=0;
for(int i=m;i>=x;i--)
L_sum=max(L_sum,tem+=a[i]);
//分治法第三步(1),从分界点开始往左的最大连续和L
tem=0;
for(int i=m+1;i<=y;i++)
R_sum=max(R_sum,tem+=a[i]);
//分治法第三步(1),从分界点开始往右的最大连续和R
return max(sum_max,L_sum+R_sum);
//把子问题的解与 (L和R的和) 比较
}
int main()
{
int n,*a;
scanf("%d",&n);
a=(int *)malloc(sizeof(int)*n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
printf("%lld\n",maxsum(a,0,n-1));
return 0;
} </span>
分治法里例子还有许多,比如比较经典的还有: 归并排序、快速排序