中科院算法课程第2节-递归与分治
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2013-4-25
20
2.5 最近点对问题
• 利用排序的算法
– 算法
• 把Q中的点排序 • 通过排序集合的线性扫描找出最近点对 – 时间复杂性 • T(n)=O(nlogn)
2013-4-25
21
2.5 最近点对问题
一维最近点对的Divide-and-conquer算法
Preprocessing:
递归与分治
Recurrence and Divide and Conquer
电子与通信工程学院
qxye@gucas.ac.cn
2013-4-25
1
提纲
2.1.合并排序问题 2.2 递归的概念 2.3.分治算法设计与分析 2.4.棋盘覆盖问题 2.5 最近点对问题 2.6.点集凸包问题
2013-4-25 2
当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1 子棋盘(a)所示。 特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特 殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可 以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所示,从 而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这 种分割,直至棋盘简化为棋盘1×1。
2013-4-25 14
2.3 分治算法—适用条件
divide-and-conquer(P) { if ( | P | <= n0) adhoc(P); //解决小规模的问题 divide P into smaller subinstances P1,P2,...,Pk;//分解问题 for (i=1,i<=k,i++) yi=divide-and-conquer(Pi); //递归的解各子问题 return merge(y1,...,yk); //将各子问题的解合并为原问题的解 } 人们从大量实践中发现,在用分治法设计算法时,最好 使子问题的规模大致相同。即将一个问题分成大小相等 的k个子问题的处理方法是行之有效的。这种使子问题规 模大致相等的做法是出自一种平衡(balancing)子问题的思 想,它几乎总是比子问题规模不等的做法要好。
2013-4-25 15
2.3 分治算法—复杂性分析
一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。 设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间。 再设将原问题分解为k个子问题以及用merge将k个子问题的解合 并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规 模为|P|=n的问题所需的计算时间,则有:
• 每个子问题大小为n/b。
• 划分时间可直接得到=D(n)
• Conquer阶段的时间复杂性
• 递归调用
• Conquer时间= aT(n/b)
• Combine阶段的时间复杂性
• 时间可以直接得到=C(n)
2013-4-25
13
2.3 分治算法—适用条件
分治法所能解决的问题一般具有以下几个特征: • 该问题的规模缩小到一定的程度就可以容易地解决; • 该问题可以分解为若干个规模较小的相同问题,即该问 题具有最优子结构性质 • 利用该问题分解出子问题的解可以合并为该问题的解; • 该问题所分解出的各个子问题是相互独立的,即子问题 之间不包含公共的子问题。
2.1 合并排序问题
1 2 2 3 4 5 6 7
2
4
5
7
1
2
3
6
2
5
4
7
1
3
2
6
5
2
4
7
1
3
2
6
2013-4-25
3
2.1 合并排序问题
• Pseudo code 递归式 Merge-Sort(A, p, r) 1. if p<r 2. then q←[(p+r)/2] 3. Merge-Sort(A, p, q) 4. Merge-Sort(A, q, r) 5. Merge(A, p, q, r);
1、采用一个用户定义的栈来模拟系统的递归调用工作栈。该方 法通用性强,但本质上还是递归,只不过人工做了本来由编译
器做的事情,优化效果不明显。
2、用递推来实现递归函数。 3、通过变换能将一些递归转化为伪递归,从而迭代求出结果。 后两种方法在时空复杂度上均有较大改善,但其适用范围有限。
2013-4-25
例:Fibonacci数列 无穷数列1,1,2,3,5,8,13,21,34,55,……,称为 Fibonacci数列。它可以递归地定义为:
1 n0 F ( n) 1 n 1 F (n 1) F (n 2) n 1
第n个Fibonacci数可递归地计算如下: int fibonacci(int n) { if (n <= 1) return 1; return fibonacci(n-1)+fibonacci(n-2); }
2013-4-25
11
2.3 分治算法—设计
原始问题
问题分解 子问题 求解子问题 子问题解 子问题 求解子问题 子问题解 合并子解
2013-4-25
Divide
… … …
子问题 求解子问题 子问题解
Conquer
Merge
12
原始问题的解
2.3 分治算法—分析
• Divide阶段的时间复杂性
• 划分问题为a个子问题。
1. 如果Q中仅包含2个点,则返回这个点对; 2. 求Q中点的中位数m。
Divide: 1. 用Q中点坐标中位数m把Q划分为两个 大小相等的子集合 Q1 = {xQ | xm}, Q2 = {xQ | x>m}
这条特征涉及到分治法的效率,如果各子问题是不独立 能否利用分治法完全取决于问题是否具有这条特征, 这条特征是应用分治法的前提,它也是大多数问 因为问题的计算复杂性一般是随着问题规模的增 的,则分治法要做许多不必要的工作,重复地解公共的 题可以满足的,此特征反映了递归思想的应用 加而增加,因此大部分问题满足这个特征。 如果具备了前两条特征,而不具备第三条特征,则 子问题,此时虽然也可用分治法,但一般用动态规划较 可以考虑贪心算法或动态规划。 好。
2013-4-25
4
2.1 ห้องสมุดไป่ตู้并排序问题
Merge(A, p, q, r)
1. 2.
3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 2013-4-25 16.
n1 ←q-p+1 n2 ←r-q
Create arrays L[1,…,n1+1] and R[1,…,n2+1] for i ←1 to n1 do L[i] ← A[p+i-1] for j ←1 to n2 do R[j] ← A[q+j] L[n1+1] ← ∞ R[n2+1] ← ∞ i ←1, j←1 for k ← p to r do if L[i] < R[j] then A[k] ← L[i] i ← i+1 else A[k] ← R[j] j = j+1
10
2.3 分治算法—设计
• 设计过程分为三个阶段
Divide:
整个问题划分为多个子问题
Conquer:求解各子问题(递归调用正设计的算法)
Combine:合并子问题的解, 形成原始问题的解
• 分析过程
– 建立递归方程 – 求解
• 递归方程的建立方法
– 设输入大小为n, T(n)为时间复杂性 – 当n<c, T(n)=(1)
2013-4-25
18
2.4 棋盘覆盖问题
void chessBoard(int tr, int tc, int dr, int dc, int size) { board[tr + s - 1][tc + s] = t; if (size == 1) return; // 覆盖其余方格 int t = tile++, // L型骨牌号 chessBoard(tr, tc+s, tr+s-1, tc+s, s);} s = size/2; // 分割棋盘 // 覆盖左下角子棋盘 // 覆盖左上角子棋盘 if (dr >= tr + s && dc < tc + s) if (dr < tr + s && dc < tc + s) // 特殊方格在此棋盘中 // 特殊方格在此棋盘中 chessBoard(tr+s, tc, dr, dc, s); chessBoard(tr, tc, dr, dc, s); else {// 用 t 号L型骨牌覆盖右上角 else {// 此棋盘中无特殊方格 board[tr + s][tc + s - 1] = t; // 用 t 号L型骨牌覆盖右下角 // 覆盖其余方格 board[tr + s - 1][tc + s - 1] = t; chessBoard(tr+s, tc, tr+s, tc+s-1, s);} // 覆盖其余方格 // 覆盖右下角子棋盘 // 覆盖右上角子棋chessBoard(tr, tc, tr+s-1, tc+s-1, s);}盘 s && dc >= tc + s) if (dr >= tr + if (dr < tr + s && dc >= tc + s) // 特殊方格在此棋盘中 // 特殊方格在此棋盘中 chessBoard(tr+s, tc+s, dr, dc, s); chessBoard(tr, tc+s, dr, dc, s); else {// 用 t 号L型骨牌覆盖左上角 else {// 此棋盘中无特殊方格 board[tr + s][tc + s] = t; // 用 t 号L型骨牌覆盖左下角 // 覆盖其余方格 chessBoard(tr+s, tc+s, tr+s, tc+s, s);} 2013-4-25 19 }
5
2.2 递归的概念
• 直接或间接地调用自身的算法称为递归算法。用函数自 身给出定义的函数称为递归函数。 • 由分治法产生的子问题往往是原问题的较小模式,这就 为使用递归技术提供了方便。在这种情况下,反复应用 分治手段,可以使子问题与原问题类型一致而其规模却 不断缩小,最终使子问题缩小到很容易直接求出其解。 这自然导致递归过程的产生。 • 分治与递归像一对孪生兄弟,经常同时应用在算法设计 之中,并由此产生许多高效、简介的算法。
2013-4-25
边界条件
递归方程
8
2.2 递归的概念
优点:结构清晰,可读性强,而且容易用数学归纳法来证明算
法的正确性,因此它为设计算法、调试程序带来很大方便。
缺点:递归算法的运行效率较低,无论是耗费的计算时间还是 占用的存储空间都比非递归算法要多。
2013-4-25
9
2.2 递归的概念
解决方法:在递归算法中消除递归调用,转化为非递归算法。
2013-4-25
6
2.2 递归的概念
例:阶乘函数 阶乘函数可递归地定义为: 边界条件
n0 1 n! n(n 1)! n 0
递归方程 边界条件与递归方程是递归函数的二个要素,递归函 数只有具备了这两个要素,才能在有限次计算后得出 结果。
2013-4-25 7
2.2 递归的概念
2.4 棋盘覆盖问题
在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不 同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋 盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的 特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不 得重叠覆盖。
2013-4-25
17
2.4 棋盘覆盖问题
O(1) n 1 T (n) kT (n / m) f (n) n 1
通过迭代法求得方程的解:T (n) n
logm k
logm n 1 j 0
k j f (n / m j )
注意:递归方程及其解只给出n等于m的方幂时T(n)的值,但 是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值 可以估计T(n)的增长速度。通常假定T(n)是单调上升的,从而 当mi≤n<mi+1时,T(mi)≤T(n)<T(mi+1)。 2013-4-25 16
2.5 最近点对问题
一维最近点对问题的定义: 输入:Euclidean空间上的n个点的集合Q 输出:P1, P2Q, Dis(P1, P2)=Min{Dis(X, Y) | X, YQ} Dis(X, Y)是Euclidean距离: 如果X=(x1, x2), Y=(y1, y2),则
Dis(X,Y) (x1 x2 )2 ( y1 y2 )2