一、介绍
分治,顾名思义,分而治之。分治法(divide and conquer)也是一种解决问题的常用模式,分治法的设计思想是将无法着手解决的大问题分解成一系列规模较小的相同问题,然后逐个解决小问题,即所谓的分而治之。分治法产生的子问题与原始问题相同,只是规模减小,反复使用分治方法,可以使得子问题的规模不断减小,直到能够被直接求解为止。
分治法作为算法设计中一个古老的策略,在很多问题中得到了广泛的应用,比如最大、最小问题(例如在一堆形状相同的物品中找出最重或最轻的那一个),矩阵乘法、大整数乘法以及排序(例如快速排序和归并排序)。除此之外,这个技巧也是许多高效算法的基础,比如快速傅里叶变换算法和Karatsuba乘法算法。
应用分治法,一般出于两个目的:一是通过分解问题,使无法着手解决的大问题变成容易解决的小问题;二是通过减小问题的规模,降低解决问题的复杂度(或计算量)。给1000个数排序,可能会因为问题的规模太大而无从下手,但是如果减小这个问题的规模,将问题一分为二,变成分别对两个拥有500个数的序列排序,然后再将两个排序后的序列合并成一个就得到了1000个数的排序结果。对500个数排序仍然无法下手,需要继续分解,直到最后问题的规模变成2个数排序的时候,只需要一次比较就可以确定顺序。这正是归并排序的实现思想,通过减小问题的规模使问题由难以解决变得容易解决。计算N个采样点的离散傅里叶变换,需要做N2次复数乘法,但是将其分解成两个N/2个采样点的离散傅里叶变换,则只需要做(N/2)2+(N/2)2=N2/2次复数乘法,做一次分解就使得计算量减少了一半,这正是快速傅里叶变换的实现思想,通过减小问题的规模减少计算量,降低问题的复杂度。
二、原理与思想
在分治策略中,我们递归地求解一个问题,在每层递归中应用如下三个步骤:
- 分解(Divide)步骤将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小。
- 解决(Conquer)步骤递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
- 合并(Combine)步骤将子问题的解组合成原问题的解。
当子问题足够大,需要递归求解时,我们称之为递归情况(recursive case)。当子问题变得足够小,不再需要递归时,我们说递归已经“触底”,进入了基本情况(base case)。有时,除了与原问题形式完全一样的规模更小的子问题外,还需要求解与原问题不完全一样的子问题。我们将这些子问题的求解看做合并步骤的一部分。
三、算法模板
Divide-and-Conquer(P)
if |P| ≤c then S(P)
divide P into P1,P2,…,Pk //将P归约成k个子问题
for i=1 to k do
yi <- Divide-and-Conquer(Pi) //递归求解每个子问题
return Merge(y1,y2,…,yk) //把子问题的解进行综合
有些题目是没有显示合并操作,只有分解和解决步骤。