这题解题思路较为巧妙。
显然 n=1 直接移动即可;所以从 n=2 开始考虑,不难得出,此时只需要 A->B,A->C,B->C
即可。
由于每次只能移动顶部圆盘,所以采用一种整体法的思维,将某个柱子的圆盘分解为两部分,即底部的一个圆盘和该柱上面剩下的全部圆盘,类比 n=2 ,假设我们知道剩下的全部圆盘怎么移动,那么只需要: 先把上面剩下的全部圆盘移到过渡柱子,然后底部圆盘移动到终点柱子,然后再把上面剩下的全部圆盘移到终点柱子。而 “剩下的全部圆盘” 怎么移动,就是一个 n'=n-1 时的子问题了,因为它恰好就是大小 1 到 n-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;
}