汉诺塔由三根柱子(分别用 A,B,C 表示)和 n个大小互不相同的空心盘子组成。一开始 n个盘子都摞在柱子 A 上,大的在下面,小的在上面,形成了一个塔状的锥形体。
对汉诺塔的一次合法的操作是指:从一根柱子的最上层拿一个盘子放到另一根柱子的最上层,同时要保证被移动的盘子一定放在比它更大的盘子上面(如果移动到空柱子上就不需要满足这个要求)。求圆盘从A到C上的最小步数。
看下图,可得到递归操作。
代码如下:
#include <iostream>
using namespace std;
int sum;
void hannoi(int n, char a, char b, char c)
{
if (n == 1) sum++;//最后一块的步数
else
{
sum++;//每一次进入步数++
hannoi(n - 1, a, c, b);//A--B通过C
hannoi(n - 1, b, a, c);//B--C通过A
}
}
int main()
{
int n = 0;
cin >> n;
hannoi(n, 'A', 'B', 'C');
cout << sum;
return 0;
}
根据上面的递归可以发现:挪动次数f(n) = 2*f(n - 1) + 1
进一步可以得到 - - > f(n) = 2^n - 1的结论
3根柱子的结论我们得出来了,那4根呢?
汉诺塔问题,条件如下:
1、这里有 A、B、C和 D 四座塔。
2、这里有 n个圆盘,n 的数量是恒定的。
3、每个圆盘的尺寸都不相同。
4、所有的圆盘在开始时都堆叠在塔 A上,且圆盘尺寸从塔顶到塔底逐渐增大。
5、我们需要将所有的圆盘都从塔 A 转移到塔 D 上。
6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。
请你求出将所有圆盘从塔 A移动到塔 D,所需的最小移动次数是多少。
4根柱子问题需要转换成我们熟知的3根柱子问题来解决:4根可以看成是j个移动到某根柱子,待最后再移(类似于3根柱子问题中最后移动到C的那个盘子),然后将其他3根柱子和盘子按照常规3柱子问题,而原本1盘的一步,变成了j盘的j步。
#include <iostream>
#include <istream>
using namespace std;
int sum;
int s[15], an[15];//存放3根柱子的 存放结果的
int main()
{
for (int i = 1; i <= 12; i++)//3根柱子的结论
s[i] = 2 * s[i - 1] + 1;
memset(an, 0x3f, sizeof an);//将an中全放无穷大的数,这样取得的数一定可以进入
an[0] = 0 ;
for(int i = 1 ; i <= 12 ; i++)//i表示盘子数
{
for (int j = 0; j < i; j++)//j为没有移动的部分(顺序操作中首次的3根问题)
{
//最优j数未知,需要遍历,比较此次与上次相比的最少步数
an[i] = min(an[i], 2 * an[j] + s[i-j]);//an[j]为顺序操作中的再次3根问题
/*
不能为an[i-j]
(此时j表示移动数),
因为j = 0时,an[i]*2+s[0] > an[i],且此时an[i]为最大数,
记录出错。
*/
}
cout <<an[i]<< endl;
}
return 0;
}