动态规划解决汉诺塔问题——清晰明了的思路

问题描述

有A,B,C三个柱子,A柱子上从上到下,从小到大排列着n个圆盘。现要求将A柱子上的n个圆盘全部移动到C柱子上,依然按照从上到下,从小到大的顺序排列。且对移动过程要求如下:

a)一次只能移动一个盘子。

b)移动过程中大盘子不允许出现在小盘子上方。

问:总共需要移动的步数是多少?

大致思路

思路简要如下:将移动步骤分为三步,

a)将最上面的n-1个盘子从A柱子移动到B柱子上

b)将最大的盘子移动到C柱子上

c)再将B柱子上的n-1个盘子移动到C柱子上

完成了。

好的,现在我们假设,f(n) 是将n个盘子从其中一个盘子移到另一个盘子的步数。

那么上面的三步就变成了:

a)所需f(n-1)

b)所需1步

c)所需f(n-1)

显然可以得到 f(n) = 2 * f(n - 1) + 1,这是个啥呢,利用高中数列知识变成

f(n) + 1 = 2(f(n - 1) + 1),令q(n) = f(n) + 1 发现没有,q(n) 是一个等比序列。

q(n) = 2^n(n >= 1)f(n) = 2^n - 1

到此,问题解决。

int hanoi(int n){
    return (1<<n)-1;
}

当然如果要打印路径,那么需要利用回溯。

int cnt=0; //步数
void move(int id, char from, char to) // 打印移动方式:编号,从哪个盘子移动到哪个盘子
{
    printf ("step %d: move %d from %c->%c\n", ++cnt, id, from, to);
}
void hanoi(int n, char x, char y, char z)   //函数的物理意义是打印n个盘子从x柱子到z柱子的路径。
{
    if (n == 0)
        return;
    //下面三个过程与思路哪儿一样,或者说就是每一步思路的代码实现
    hanoi(n - 1, x, z, y);    //先要把上面的n-1个盘子从x柱子移动到y柱子,打印这个过程的路径
    move(n, x, z);           //然后把第n个盘子从x柱子移到z柱子,打印这次移动
    hanoi(n - 1, y, x, z);   //把y柱子上n-1个盘子从y柱子移动到z柱子,也打印这个过程的路径
}
posted on 2021-06-10 16:43  雾恋过往  阅读(328)  评论(0编辑  收藏  举报

Live2D