汉诺塔III--【C语言】 递归和普通算法,看似简单实则大坑不断


Description
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。

Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
Input
包含多组数据,每次输入一个N值(1<=N=35)。
Output
对于每组数据,输出移动最小的次数。
Sample Input
1
3
12
Sample Output
2
26
531440

递归,容易理解,但会超时

如果只有一个盘子,从X到Y再到Z,要两步
如果有n个盘子
在这里插入图片描述
先把n-1个盘子从X借助Y移动到Z,再把最大的盘子移动到Y
在这里插入图片描述

之后把n-1个盘子从Z借助Y移动到X,再把最大的盘子移动到Z
在这里插入图片描述

此时问题规模减小,变成了把n-1个盘子从X借助Y移动到Z
在这里插入图片描述

code

#include <stdio.h>
int count=0; 
int hanota(int n,char x,char y,char z);
int main()
{
	int n;
	while(scanf("%d",&n)!=0){
		count=hanota(n,'x','Y','Z');
		printf("%d\n",count); 
		count=0;//对计数器清零,方便下次使用
	}
}
int hanota(int n,char x,char y,char z)
{
	if(n==1){
		count+=2;//从X到Y到Z,两步
	}
	else{
		hanota(n-1,'X','Y','Z');//把n-1个盘子从X借助Y移到Z
		count++;
		hanota(n-1,'Z','Y','X');//把n-1个盘子从Z借助Y移到X
		count++;
		hanota(n-1,'X','Y','Z');
	}
	return count;
}
string='''但是超时就很难受啊,本来递归就想了一阵,提交一秒不到就是Time Limit Exceeded,就很伤(fan)心(zao)啊'''
print(string)

普通算法(有大坑)

当用递归测试了几组数据之后,会发现其满足递推式an=3^n-1;
下面我们来推导一番
设汉诺塔函数为F(n)
有n个盘子,我们要把(n-1)个盘子先移到Z,共F(n-1)步,把大盘子移到Y,又是一步,接着把(n-1)个盘子移到X,有F(n-1)步,把大盘子移到Z,又是一步,最后把重新把(n-1)个盘子移到Z,又是F(n-1)步。
不难看出F(n)=F(n-1)*3+2,结合初始条件(n=1时)就可以得出
an=3^n-1

正确代码(等下举几个错误例子)

#include<stdio.h>
#include<math.h>
int main()
{
	int n,i;
	long long int step=1;
	while(scanf("%d",&n)!=EOF){
		long long int step=1;
		for(i=1;i<=n;i++)
			step*=3;
		step-=1;
		printf("%lld\n",step);
	}
}

注意

扫描二维码关注公众号,回复: 11178601 查看本文章
for(i=1;i<=n;i++)
   step*=3;
  step-=1;

这段代码在这里不能写成

step=pow(3,n)-1;

因为pow()精度的问题,当数字很大时会出错

还有一个大坑

printf("%lld\n",step);

不能写成

printf("%d",step);

为什么会这样,一开始我也不知道,不管怎么改动都是Wrong Answer,之后发现了这个问题
这个坑也不是我一句两句能说清楚的
详情请参考%I64d 和%lld 的区别传送门1
或者传送门2

原创文章 27 获赞 26 访问量 7779

猜你喜欢

转载自blog.csdn.net/unseven/article/details/105508906