标签:
第一部分:题目
汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题。在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我A上(如图所示),你的目标是在最少的合法移动步数内将所有盘子从A塔移动到C塔。
游戏中的每一步规则如下:
1. 每一步只允许移动一个盘子(从一根柱子最上方到另一个柱子的最上方)
2. 移动的过程中,你必须保证大的盘子不能在小的盘子上方(小的可以放在大的上面,最大盘子下面不能有任何其他大小的盘子)
如对于n=3的情况,一个合法的移动序列式:
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
给出一个数n,求出最少步数的移动序列
一个整数n
第一行一个整数k,代表是最少的移动步数。
接下来k行,每行一句话,N from X to Y,表示把N号盘从X柱移动到Y柱。X,Y属于{A,B,C}
3
7
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
n<=10
第二部分:思路
这里使用的是递归。想象一下,要把一个盘子从A->C,只需要一步:1 from A to C.把2个盘子从A->C:要先把2从A->B,然后把1从A->C,最后把2从B->C;规律就是:当N>1时,先把N-1个上面的盘子移到目标柱子的另外一个柱子(这里称为 伪目标柱子),然后把N从当前柱子移到目标柱子,最后把N-1个盘子从伪目标柱子移到目标柱子。从这里可以得出,最少步骤等于2的n次方减1.
第三部分:代码
#include<stdio.h> void show(int n,char now,char target)//now 表示当前盘子所在柱子,target表示目标柱子 { if(n==1)//如果当前只需要把1个盘子从now 移到target,那么就直接移过去 { printf("%d from %c to %c\n",n,now,target); } else { if(target==‘C‘)//当有多个盘子时,需要先把上面n-1个盘子先移到除now 和target外的第三个柱子,这里称之为伪目标柱子,可想而知,伪目标柱子是未知的,需要进行判断 { if(now==‘A‘) { show(n-1,now,‘B‘);//把n-1个上面的盘子移到伪目标柱子 printf("%d from %c to %c\n",n,now,target);//把n号盘子移到目标柱子 show(n-1,‘B‘,target);//把n-1个上面的盘子移到目标柱子,“此处一定要注意,不要丢了”。下面是其他情况,原理一样 } else { show(n-1,now,‘A‘); printf("%d from %c to %c\n",n,now,target); show(n-1,‘A‘,target); } } if(target==‘B‘) { if(now==‘A‘) { show(n-1,now,‘C‘); printf("%d from %c to %c\n",n,now,target); show(n-1,‘C‘,target); } else { show(n-1,now,‘A‘); printf("%d from %c to %c\n",n,now,target); show(n-1,‘A‘,target); } } if(target==‘A‘) { if(now==‘B‘) { show(n-1,now,‘C‘); printf("%d from %c to %c\n",n,now,target); show(n-1,‘C‘,target); } else { show(n-1,now,‘B‘); printf("%d from %c to %c\n",n,now,target); show(n-1,‘B‘,target); } } } } int main() { int n,sum=1,i; scanf("%d",&n); for(i=1;i<=n;i++)//根据规律得出最少步骤是2的n次方减1 { sum*=2; } sum--; printf("%d\n",sum); show(n,‘A‘,‘C‘);//n个盘子要从柱子A移到柱子B return 0; }
3145 汉诺塔游戏——http://codevs.cn/problem/3145/
标签:
原文地址:http://www.cnblogs.com/xiangguoguo/p/5343019.html