汉诺塔问题
描述:有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置n个金盘。
目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
思路分析
初始状态是需要将A处的n层全部移到C处,B可借助。此时,我们可以把n-1层以上的盘子当作一个整体,借助B处我们可以将A的n-1层以上移到B处,然后才可以把n层移到C处。此时的状态就变成了需要将B处的n-1层移到C处,A可借助。以此类推,下一个状态可变为将A处的n-2层移动到C处,B可借助 ,................,最后一个状态变为将A/B处的1层移动到C处,B/A可借助。
也就是如下的思路步骤:
- 以C盘为中介,从A杆将1至n-1号盘移至B杆;
- 将A杆中剩下的第n号盘移至C杆;
- 以A杆为中介;从B杆将1至n-1号盘移至C杆。
#include<iostream>
using namespace std;
int Hanoi(int n,char A,char B,char C){
if(n==1){
cout<<A<<"--->"<<C<<endl;
return 1;
}
int count1 = Hanoi(n-1,A,C,B);//将n-1个盘从A--->B
cout<<A<<"--->"<<C<<endl;
int count2 = Hanoi(n-1,B,A,C);//将n-1个盘从B--->C
return count1+count2+1; //将最下层移到C需要+1
}
int main(){
int n;
cout<<"输入A处盘的数目:";
cin>>n;
cout<<"一共需要移动次数:"<<Hanoi(n,'A','B','C');
return 0;
}
这样下来我们就将一个复杂的大型问题不断分化为一个越来越小的问题直到可以方便地解决,然后在回溯回去,达到解决大型问题的目的。这种思想就是分治的思想。
正像分封土地一样,分治法的目的就是为了把无法解决的大问题分解成若干个能够解决小问题。通常来说,分治法可以归纳为三个步骤:
1. 分解,将原问题分解成若干个与原问题结构相同但规模较小的子问题;
2. 解决,解决这些子问题。如果子问题规模足够小,直接求解,否则递归地求解每个子问题;
3. 合并,将这些子问题的解合并起来,形成原问题的解。
下面我们谈谈分治与递归!
分治与递归区别
分治是把一个问题分解成无数个重复移动的动作的思维方法,而递归则是进行一个重复的循环while语句控制好边界直到解决问题。其实对于这个区别,界限也并非如此清晰,你可以想象,如果我让一万个1相加。采用循环,直接循环加一万次;采用递归,递归循环一万次;采用分治,不停的划分(这里划分既可以使用递归也可以使用循环),两两相加。
递归算法
递归其实是直接或者间接不断反复调用自身来达到解决问题的方法。要求原始问题可以分解为相同问题的子问题。、
需要:1 递归边界 2 自身调用
特点分析:递归思路简单清晰,如果分析出将很快得到结果;递归将多次调用,使用到堆栈,算法效率低,费时费内存。
常用场景:阶乘,斐波纳契数列、汉诺塔问题,整数划分,枚举排列及二叉树,图的搜索相关问题。
分治算法
一、分治算法主要特点是三点
- 将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题—-“分”
- 将最后子问题可以简单的直接求解—-“治”
- 将所有子问题的解合并起来就是原问题打得解—-“合”
这是分治算法的主要特点,只要是符合这三个特点的问题都可以使用分治算法进行解决(可以用,效果好不好再说)。
二、分治法所能解决的问题一般具有以下几个特征
- 该问题的规模缩小到一定的程度就可以容易地解决
- 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
- 利用该问题分解出的子问题的解可以合并为该问题的解;
- 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;
第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、
第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。
第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。
三、分治法求解的一些经典问题
- 二分搜索
- 大整数乘法
- Strassen矩阵乘法
- 棋盘覆盖
- 合并排序
- 快速排序
- 线性时间选择
- 最接近点对问题
- 循环赛日程表
- 汉诺塔问题
四、依据分治法设计程序时的思维过程
实际上就是类似于数学归纳法,找到解决本问题的求解方程公式,然后根据方程公式设计递归程序。
- 一定是先找到最小问题规模时的求解方法;
- 然后考虑随着问题规模增大时的求解方法;
- 找到求解的递归函数式后(各种规模或因子),设计递归程序即可。
参考:https://blog.youkuaiyun.com/tianjing0805/article/details/75738698