- 分治
分治
总体思想
- 将要求解的较大规模的问题分割成k个更小规模的子问题
- 对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k为子问题,如此递归进行下去,直到问题规模足够小,很容易求出其解为止
- 将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来的问题的解
使用条件
- 该问题的规模缩小到一定的程度就可以容易地解决
- 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
- 利用该问题分解出的子问题的解可以合并为该问题的解
- 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题
能否利用分治法完全取决于子问题是否具有这条特征,如果具备了前两条特征,而不具备第三条特征,则可以考虑贪心算法或动态规划
基本步骤
案例
覆盖残缺棋盘
- 在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。
- 用 (n2) / 3个三重格放置在 n × n 的缺陷棋盘上,正好能够覆盖所有方格
具体步骤:
- 划分为四个小棋盘
- 其中一个是 4 × 4 缺陷棋盘
- 在其他三个 4 × 4 棋盘都都相邻的拐角上放一个三格板,使它们也成为缺陷棋盘
- 递归地覆盖四个4×4缺陷棋盘
- 在其它三个 4 × 4 棋盘都相邻的拐角上放一个三格板,使它们也成为缺陷棋盘。
Java代码实现
大整数的乘法
- 小学的方法:效率太低 O(n2)
- 分治法:
- X = A × 2n/2+ B
Y = C × 2n/2+ D
XY = (A × 2n/2+ B)(C × 2n/2+ D)
=AC × 2n+ (AD + CB) × 2n/2+ BD - 实质上没有改进
再次进行改进:
XY = AC × 2n+ (AD + CB) × 2n/2+ BD
=AC × 2n+ ((A - B)(D - C) + AC + BD) × 2n/2+ BD
这样只需进行3次 n/2 位乘法 - T(n) = O(nlog3) = O(n1.59) (有了较大的改进)
如果将大整数分成更多段,用更复杂的方式把它们组合起来,将有可能得到更优的算法
Strassen矩阵乘法
易知,时间复杂度为 O(n3)
分治法:
- 将矩阵A、B和C中每一矩阵都分成4个大小相等的子矩阵,则 C = AB 可写为:
- 由此可得:
- 实际复杂度还是没有变,仍然为 O(n3)
- 为了降低时间复杂度,要减少乘法的次数
- 这样,复杂度得到了改进