一、分治概述
分治法是的核心:将一个复杂的问题拆分成多个易解决的小问题。
分治法的三个基本步骤:
1. 分解:原问题分解为子问题
2. 解决:对每个子问题进行求解
3. 合并:合并子问题的解得出原问题的解
二、fibonacci问题
先看一个简单的例子:
description: f(1) = f(2) = 1, f(n) = f(n-1) + f(n-2) (n>2).
input: 一个整数n.
output: f(n)
让我们用分治的思想来解这个问题:
1. 分解:f(n)分解为求f(n-1)和f(n-2)。
2. 解决:递归解出f(n-1)和f(n-2)。
3. 合并:f(n) = f(n-1) + f(n-2)。
1 int f(int n) 2 { 3 if(1==n || 2==n) 4 return 1; 5 return f(n-1)+f(n-2); 6 }
三、汉诺塔问题
现在看一个更复杂一点的例子,同样是个很熟悉的题目
description: 有A, B, C三个圆柱,其中A上从上至下放置了从小到大n个圆盘,一次只能移动一个圆盘,且大的圆盘不能放在小圆盘之上,要求打印出从A将圆盘移到C的方案。
这个问题明显要比fibonacci难一些,不是很容易想出分解的方案。
首先分析最简单的情况:
n=1时,我们的操作是:1,A->C,问题解决。
n=2时,1,A->B; 2,A->C; 3,B->C,问题解决。
我们发现,n>2时盘子的移动跟n=2其实没什么两样:先将前n-1个盘子移动到B,再将第n个盘子移动到C,最后将前n-1个盘子移动到C。这就是一个递归过程!
1 void move(int n, char x, char y) 2 { 3 cout<<n<<", "<<x<<"->"<<y<<endl; 4 } 5 void hanoi(int n, char a, char b, char c) 6 { 7 if(1==n) 8 move(n, a, c); 9 else 10 { 11 hanoi(n-1, a, c, b); 12 move(n, a, c); 13 hanoi(n-1, b, a, c); 14 } 15 }
hanoi(int n, char a, char b, char c)是主要函数。其中n代表圆盘个数,a、b、c分别是起始圆柱,辅助圆柱,目的圆柱。
四、分治的缺陷
回到fibonacci,我们发现求解f(n-1)的时候已经求解出了f(n-2),接着我们又求了一遍,其原因在于分治把子问题均看作独立互不相关的个体!这导致了分治的时间复杂度往往偏高。
五、总结
1. 分治的关键是分解问题。
2. 分治解决问题的步骤通常是用的递归。
3. 分治的子问题是互不相关的。
浙公网安备 33010602011771号