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