mageover

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、分治概述

  分治法是的核心:将一个复杂的问题拆分成多个易解决的小问题。

  分治法的三个基本步骤:

  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. 分治的子问题是互不相关的。

posted on 2013-10-29 13:49  mageover  阅读(315)  评论(0)    收藏  举报