1594. 汉诺塔

这题解题思路较为巧妙。

显然 n=1 直接移动即可;所以从 n=2 开始考虑,不难得出,此时只需要 A->B,A->C,B->C 即可。

由于每次只能移动顶部圆盘,所以采用一种整体法的思维,将某个柱子的圆盘分解为两部分,即底部的一个圆盘和该柱上面剩下的全部圆盘,类比 n=2 ,假设我们知道剩下的全部圆盘怎么移动,那么只需要: 先把上面剩下的全部圆盘移到过渡柱子,然后底部圆盘移动到终点柱子,然后再把上面剩下的全部圆盘移到终点柱子。而 “剩下的全部圆盘” 怎么移动,就是一个 n'=n-1 时的子问题了,因为它恰好就是大小 1n-1 的盘。这意味着,当已知 n-1 的移动方案时,便可以根据上面的做法推知 n 的移动方案。而且这种做法不会产生违背“小圆盘不能放在大圆盘"的条件。

如果反过来设状态,即:拆分为顶部一个和剩下全部,那么无法将原问题分解为子问题。

n=3 为例,根据上面思路第一步就是先把头两个盘移动到 B ,起点是 A ,显然不借助过渡是不行的,所以可以拿 C 来过渡;即第一步是起点为 A ,终点为 B ,过渡为 C 的子问题。接着第二步,直接把 A 底部圆盘移动到 C 。接着第三步,把 B 的两个圆盘移动到 C ,借助 A 过渡。第一步和第三步都可以直接化用 n=2 时的答案,只需要重新把 A,B,C 改成对应起点、过渡、终点柱子即可。

因此,可以定义操作 f(n,a,b,c) ,代表 n 个圆盘要从起点柱子 a ,借助过渡柱子 b 移动到终点柱子 c 。那么有: f(n,a,b,c)=f(n-1,a,c,b)+\ A- > C\ +f(n-1,b,a,c) n>1 时,都需要如此执行; n=1 时,直接移动即可,即: f(1,a,b,c)=A- > C 因此,代码如下:

#include <stdio.h> void hanio(char a, char b, char c, int n) { if (n > 1) hanio(a, c, b, n - 1); printf("%c->%c\n", a, c); if (n > 1) hanio(b, a, c, n - 1); } int main() { int n; scanf("%d", &n); hanio('A', 'B', 'C', n); return 0; }