分治法(Devide and Conquer)的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的几个相似问题,以便各个击破,分而治之。
算法设计思想
分治法求解问题的过程是,将整个问题分解成若干个小问题后分而治之。如果分解得到的子问题相对来说还太大,则可反复使用分支策略将这些子问题分成更小的同类型子问题,直至成生出方便求解的子问题,必要时逐步合并这些子问题的解,从而得到问题的解。
由算法思路可知,分治法求解很自然地可以用一个递归过程来表示。可以这样说,分治方法就是一种找大规模问题与小规模问题关系的方法,是递归设计方法的一种具体策略。分治法的基本步骤在每一层递归上都有3个步骤:
1、分解:将原问题分解为若干规模较小,相互独立,与原问题形式相同的子问题;
2、解决:若子问题规模较小而容易被解决,则直接解决,否则再继续分解为更小的子问题,知道容易解决;
3、合并:将已求解的各个子问题的解逐步合并为原问题的解。
有时候问题分解后,不必求解所有的子问题,也就不必做第三步的操作,例如折半查找。多数问题需要所有子问题的解,并由子问题的解使用恰当的方法合并成为整个问题的解,例如归并排序。
适用分治法策略的问题
当求解一个输入规模为n且取值又相当大的问题时,用蛮力策略效率一般得不到保证。若问题能满足以下几个条件,就能用分治法来提高解决问题的效率。
1、能将这n个数据分解成k个不同的子集合,且得到k个子集合是可以独立求解的子问题,其中1<k<=n;
2、分解所得到的子问题与原问题具有相似的结构,便于利用递归或循环机制;
3、在求出这些子问题的解之后,就可以推解出原问题的解。
算法框架
分治法的一般算法设计模式如下:
Devide_and_Conquer(n) //n为问题规模{ if (n<=n0) //n0为子问题规模 { 解子问题; return (子问题的解); } for (i=1;i<=k;i++) //分解为较小的k个子问题P1,P2,…,Pk { 分解原问题为更小的子问题Pi; yi=Devide_and_Conquer(|Pi|);//递归解决Pi,|Pi|为Pi的规模 } T=Merge(y1,y2,…,yk); //合并子问题 return (T);}
其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。算法Merge(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1,P2,...,Pk的相应的解y1,y2,...,yk合并为P的解。在一些问题中不需要这一步,如折半查找、二叉排序树查找等算法。