汉诺塔

Problem Description
古老的汉诺塔问题是:用最少的步数将N个半径互不相等的圆盘从1号柱利用2号柱全部移动到3号柱,在移动的过程中小盘要始终在大盘的上面。
现在在加上一个条件,不允许直接把盘从1号柱移动到3号柱,也不允许直接把盘从3号柱移动到1号柱。
把盘按半径从小到大用1-N编号。每种状态用N个整数表示,第i个整数表示i号盘所在的柱的编号。则N=2时的移动方案为(1,1)->(2,1)->(3,1)->(3,2)->(2,2)->(1,2)->(1,3)->(2,3)->(3,3),初始状态为第0步,编程求在某步数的状态。
Input
输入的第1行为整数T(1<=T<=50000),表示输入数据的组数。
接下来T行,每行有两个整数N,M(1<=N<=19,0<=M<=移动N个圆盘所需的步数)。
Output
对于每组输入数据,输出N个整数表示移动N个盘在M步时的状态,每两个数之间用一个空格格隔开,行首和行尾不要有多余的空格。
Sample Input
4
2 0
2 5
3 0
3 1
Sample Output
1 1
1 2
1 1 1
2 1 1
/*
题解: 与一般的汉诺塔不同,一般汉诺塔的递推公式是:F[N] = F[N-1] + 1 + F[N-1];
这题的递推公式是:F[N] = F[N-1] + 1 + F[N-1] + 1 + F[N-1];
一般汉诺塔的递归:
hanoi(n-1,a,c,b);
mov(n,a,c);
hanoi(n-1,b,a,c);
本题的递归:
hanoi(n-1,a,b,c);
mov(n,a,b);
hanoi(n-1,c,b,a);
mov(n,b,c);
hanoi(n-1,a,b,c);
*/

//标程:
#include<iostream>
#include<cstdio>
using namespace std;
__int64 a[25];
int p[25];
void hnt(int l1, int l2, int l3, __int64 n, __int64 m)
{
	if(n == 0)  return ;
	if(m < a[n-1] + 1)
	{
		p[n] = l1;
		hnt(l1, l2, l3, n-1, m);
		return ;
	}
	if(m < a[n-1] + 1 + a[n-1] + 1)
	{
         p[n] = l2;
		 hnt(l3,l2,l1,n-1,m-(a[n-1]+1));
		 return ;
	}
	p[n] = l3;
    hnt(l1,l2,l3,n-1,m-(a[n-1]+1+a[n-1]+1));
}
int main()
{
//	freopen("a.txt","r",stdin);
    __int64 i, n, m;
	a[0] = 0;
    for(i = 1; i <= 19; ++ i) 
		a[i] = a[i-1] + 1 + a[i-1] + 1 + a[i-1];
	int t;
	cin >> t;
	while(t --)
	{
        scanf("%I64d%I64d\n",&n,&m);
		for(i = 1; i <= n; ++ i) 
			p[i] = 1;
		hnt(1,2,3,n,m);
		cout << p[1];
		for(i = 2; i <= n; ++ i)
			cout << " " << p[i];
		cout << endl;
	}
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值