ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第二章 递归与分治策略思维导图

2021-10-10 14:59:23  阅读:177  来源: 互联网

标签:比赛 递归 导图 分治 矩阵 选手 日程 乘法


递归与分治法

递归


直接或间接调用自身的算法。

分治法


将规模为n的问题分为k个规模较小的子问题。子问题和原问题相同且相互独立。递归地解决子问题并将子问题的解合并为原问题的解。

一般而言,将问题分为大小相近的子问题是最有效率的。通常将问题一分为二。

从设计模式可以看出,分治法一般用递归实现。所以分治法的效率可以通过递归表达式进行分析。则有:

T(n)=O(1) n=1

T(n)=kT(n/m)+f(n) n>1

其中问题规模最小为1,其时解所耗费的时间为常数单位。规模大于1时,将问题分解为k个规模为n/m的子问题。将这k个子问题的解合并耗费的时间为f(n)。则展开上式可得:

T(n)=n^{log_{m}k}+\sum_{j=0}^{log_{m}n-1}k^{j}f(n/m^{j})

经典分治算法


二分搜索:


将数组分为两半,将中间元素和目标比较,根据结果对左边或右边递归进行二分搜索。

合并排序:


将数组分为等长的两半,对两个子数组递归进行合并排序,然后再把两个有序的子数组合并。

快速排序:


以数组中特定元素为基准,把数组分为比它大和比它小的两部分,再对两部分递归进行快速排序。

Strassen矩阵乘法:

n阶矩阵A和B相乘,可以分解为其子矩阵的乘法:

\begin{bmatrix} C_{11} &C_{12} \\ C_{21} &C_{22} \end{bmatrix} = \begin{bmatrix} A_{11} &A_{12} \\ A_{21} &A_{22} \end{bmatrix}\begin{bmatrix} B_{11} &B_{12} \\ B_{21} &B_{22} \end{bmatrix}

即:

\begin{matrix} C_{11} = A_{11}B_{11}+A_{12}B_{21}\\ C_{12} = A_{11}B_{12}+A_{12}B_{22}\\ C_{21} = A_{21}B_{11}+A_{22}B_{21}\\ C_{22} = A_{21}B_{12}+A_{22}B_{22} \end{matrix}

然后子矩阵的乘法再分解,直到子矩阵规模为2*2.

但这种拆分没有减少矩阵乘法次数,时间复杂度和直接做矩阵乘法没有差别。故Strassen提出了新的算法:

首先算出7个矩阵:

\begin{matrix} M_1 = A_{11}(B_{12}-B_{22})\\ M_2 = (A_{11}+A_{12})B_{22}\\ M_3 = (A_{11}+A_{22})B_{11}\\ M_4 = A_{22}(B_{21}-B_{11})\\ M_5 = (A_{11}+A_{22})(B_{11}+B_{22})\\ M_6 = (A_{12}-A_{22})(B_{21}+B_{22})\\ M_7 = (A_{11}-A_{21})(B_{11}+B_{12}) \end{matrix}

然后有

\begin{matrix} C_{11} = M_5+M_4-M_2+M_6\\ C_{12} = M_1+M_2\\ C_{21} = M_3+M_4\\ C_{22} = M_5+M_1-M_3-M_7 \end{matrix}

这样只需7次子矩阵乘法就完成了矩阵相乘,算法复杂度为O(n^{log7})\approx O(n^{2.81})

最接近点对问题

分治法:

  • 分解:将n个点的集合分成大小近似相等的两个子集。
  • 求解:递归地求解两个子集内部的最接近点对。
  • 合并(关键问题):从子空间内部最接近点对,和两个子空间之间的最接近点对中,选择最接近点对。

大整数乘法

对这个式子,我们一共要进行4次 n / 2的乘法(AC2次, AD, BC)和 3次加法,因而该算法的时间复杂度为:

T(n) = 4 * T(n / 2) + θ(n) 
通过master定理可以求得 T(n) = θ(n ^ 2),跟小学算法的时间复杂度没有区别。

但是我们再来看看,我们是否可以用加法来换取乘法?因为多一个加法操作,也是常数项,对时间复杂度没有影响,如果减少一个乘法则不同。

XY=AC2^n+[(A-B)(D-C)+AC+BD]2^n/2+BD

现在的时间复杂度为:

T(n) = 3 * T(n / 2) + θ(n),通过master定理求得,T(n) = O(n^log2(3) ) = O(n^1.59 )。

棋盘覆盖

       为了将这 3 个无特殊方格的子棋盘转化为特殊棋盘,我们可以用一个 L 型骨牌覆盖这 3 个较小的棋盘的汇合处,如下图所示,这 3 个子棋盘上被 L 型骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题化为 4 个较小规模的棋盘覆盖问题。

       每次将棋盘分成四块大小相同的子棋盘,看作四个象限,判断特殊方格在哪一个象限,将四个子棋盘交界处的方格填充(除了特殊方格所在象限),然后递归对左上,右上,右下,左下进行填充(特殊方格为已填充的点)  

循环赛日程表

按照分治的策略,可将所有参赛的选手分为两部分,n=2k个选手的比赛日程表就可以通过为\frac{n}{2}=2k-1个选手设计的比赛日程表来决定。递归地执行这种分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单:只要让这2个选手进行比赛就可以了。

显然,这个求解过程是自底向上的迭代过程,其中左上角和左下角分别为选手1至选手4以及选手5至选手8前3天的比赛日程,据此,将左上角部分的所有数字按其对应位置抄到右下角,将左下角的所有数字按其对应位置抄到右上角,这样,就分别安排好了选手1至选手4以及选手5至选手8在后4天的比赛日程,如图©所示。具有多个选手的情况可以依此类推。

这种解法是把求解2^{k} 个选手比赛日程问题划分成依次求解2{1}、2{2}、…、2{k}个选手的比赛日程问题,换言之,2{k}个选手的比赛日程是在2^{k-1}个选手的比赛日程的基础上通过迭代的方法求得的。在每次迭代中,将问题划分为4部分:

(1)左上角:左上角为2^{k-1}个选手在前半程的比赛日程;

(2)左下角:左下角为另2{k-1}个选手在前半程的比赛日程,由左上角加2{k-1}得到,例如2{2}个选手比赛,左下角由左上角直接加2得到,2{3}个选手比赛,左下角由左上角直接加4得到;

(3)右上角:将左下角直接抄到右上角得到另2^{k-1}个选手在后半程的比赛日程;

(4)右下角:将左上角直接抄到右下角得到2^{k-1}个选手在后半程的比赛日程;

标签:比赛,递归,导图,分治,矩阵,选手,日程,乘法
来源: https://blog.csdn.net/qq_52616965/article/details/120685777

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有