解决 汉诺塔 2,3,4

参考HDU2064和2077

汉诺塔2:a,b,c三柱,n个圆盘,大的不能放在小的上面,每次移动一个
汉诺塔3:a,b,c三柱,n个圆盘,大的不能放在小的上面,每次移动一个,且只能在相邻柱子之间移动
汉诺塔4:a,b,c三柱,n个圆盘,大的不能放在小的上面,每次移动一个,且只能在相邻柱子之间移动;(加上一个特例:只有最大的圆盘可以放在小的上面,即第n个圆盘

一个一个解决:
声明:
1.文中x1->x2表示从x1移动一个圆盘到x2
2.函数名mx(int n,a,b,c)表示从a移动n个圆盘经过b到c
汉诺塔2
当n==1;a柱只有一个圆盘,直接a->c
当n>1;先将a柱的n-1个圆盘移动到b,然后a->c,将剩下的n-1个圆盘从b移动到c;

m1(int n,a,b,c){
if(n==1) a->c;
else{
m1(n-1,a,c,b);
a->c;
m1(n-1,b,a,c);
}
}

可以得出
1.m(1)=1
2.m(n)=m(n-1)*2+1;
然后不论使用函数递归还是数组递归都可以解决问题,不过要提醒,在刷题是用函数递归因为时间超出是不能提交成功的。下面两种情况也是如此,我会在汉诺塔4中详细说明两种代码,前两种不予解决问题代码

汉诺塔3:
1.当n==1时,直接a到b到c
2.当n>1时,先把n-1个圆盘由a移动到c,在把第n个圆盘从a移动到b,在把n-1个圆盘从c移动到a,在把第n个圆盘从b移动到c

m1(int n,a,b,c){
if(n==1)a->b->c;
else{
m1(n-1,a,b,c);
a->b;
m1(n-1,c,b,a);
b->c;
m1(n-1,a,b,c);
}
}

由此可以得到
1.m1(1)=1
2.m1(n)=m1(n-1)*3+2;

汉诺塔4(题目来源HDU2077):
这个问题网上的答案我只能说我看不懂,看的懂就不会费这些时间研究了!

先给出我最开始的想法:

函数m(int n,a,b,c)(附:解决汉诺塔4问题)
当n==1; 直接a->b->c;
当n>1;先把n-1圆盘从a移动到b,在把第n个圆盘a->b->c;然后把n-1个圆盘从b移动到c;

函数m1(int n,a,c,b) (附:解决函数m中的"把n-1个圆盘从a移动到b"

当n==1;直接b->c;
当n>1;先把n-1个圆盘从a移动到c;再把第 n个圆盘从a移动到b;再把n-1个圆盘从c移动到b
m1(int n,a,c,b)
{

if(n==1)a->b;
else{
m3(n-1,a,b,c);
a->b;
m1(n,c,a,b);
}

函数m2(int n,b,a,c)(附:解决函数m中“把n-1个圆盘从b移动到c
当n==1;直接直接b->c
当n>1:先把n-1个圆盘从b移动到a;再把第n个圆盘从b移动到c;再把n-1个圆盘从a移动到c

m2(int n,b,a,c){
if(n==1)b->c;
else{
m2(n-1,b,c,a)
b->c;
m3(n-1,a,b,c);
}

函数m3(int n,a,b,c)(附:解决m1中“先把n-1个圆盘从a移动到c”和m2中的“再把n-1个圆盘从a移动到c
当n==1;直接a->b->c
当n>1;先将n-1个圆盘从a移动到c;再把第n个圆盘从a移动到b;再把n-1个圆盘从c移动到a;再把第n个圆盘从b移动到c;再把n-1个圆盘从a移动到c

m3(int n,a,b,c)
{
if(n==1) a->b->c;
else{
m3(n-1,a,b,c);
a->b;
m3(n-1,c,b,a);
b->c;
m3(n-1,a,b,c);
}

下面附上我递归函数的代码:

#include <stdio.h>
int c;
void m1(int n);
void m3(int n);
void m(int n){

if(n==1)c+=2;
else{
	m1(n-1);
	c+=2;
	m1(n-1);
}

}

void m1(int n){

if(n==1)c+=1;
else{
	m3(n-1);
	c+=1;
	m1(n-1); 
}

}

void m3(int n){

if(n==1)c+=2;
else{
	m3(n-1);
	c+=1;
	m3(n-1);
	c+=1;
	m3(n-1); 
}

}
int main(){

int n,l;
scanf("%d",&n);
while(n--){
	c=0;
	scanf("%d",&l);
	m(l);
	printf("%d\n",c);
}

}

全局int用来记住总共移动次数,可以解决问题,但时间超了,提交失败

上面的几个函数可以总结为
m(n)=m1(n-1)+m2(n-1)+2;
m1(n)=m3(n-1)+m1(n-1)+1;
m2(n)=m2(n-1)+m3(n-1)+1;
m3(n)=m3(n-1)*3+2;

发现m1和m2函数似乎作用一样,把m2全部改为m1
m(n)=m1(n-1)*2+2;
m1(n)=m1(n-1)+m3(n-1)+1;
m3(n)=m3(n-1)*3+2;

这里动用数组解决:
题目里面的n最大为20,所以我先算出m1数组和m3数组的前20项目;最后简单调用,
提交成功

#include <stdio.h>

int main(){

int n,num;
scanf("%d",&n);
long long m,m1[20],m3[20];
m3[0]=2;m1[0]=1;
for(int i=1;i<20;i++){
	
	m3[i] = m3[i-1]*3+2;
	m1[i] = m1[i-1]+m3[i-1]+1;
}
while(n--){
	scanf("%d",&num);
	m =(num==0)?0:((num==1)?2:2*m1[num-2]+2);
	printf("%lld\n",m);
}

}
(全程码字,无功有苦,见谅)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值