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; }