题目:
1,2,…,n表示n个盘子.数字大盘子就大.n个盘子放在第1根柱子上.大盘不能放在小盘上.在第1根柱子上的盘子是a[1],a[2],…,a[n]. a[1]=n,a[2]=n-1,…,a[n]=1.即a[1]是最下面的盘子.把n个盘子移动到第3根柱子.每次只能移动1个盘子,且大盘不能放在小盘上.问第m次移动的是哪一个盘子,从哪根柱子移到哪根柱子.例如:n=3,m=2. 回答是 :2 1 2,即移动的是2号盘,从第1根柱子移动到第2根柱子 。
Input
第1行是整数T,表示有T组数据,下面有T行,每行2个整数n (1 ≤ n ≤ 63) ,m≤ 2^n-1
Output
输出第m次移动的盘子号数和柱子的号数.
Sample Input
4
3 2
4 5
39 183251937942
63 3074457345618258570
Sample Output
2 1 2
1 3 1
2 2 3
2 2 3
分析:
汉诺塔
一号柱有n个盘子,叫做源柱.移往3号柱,叫做目的柱.2号柱叫做中间柱.
全部移往3号柱要f(n)=(2n)−1f(n)=(2^n)-1f(n)=(2n)−1次.
最大盘n号盘在整个移动过程中只移动一次,n-1号移动2次,i号盘移动2(n−i)2^{(n-i)}2(n−i)次.
1号盘移动次数最多,每2次移动一次.
第2k+1次移动的是1号盘,且是第k+1次移动1号盘.第4k+2次移动的是2号盘,且是第k+1次移动2号盘.
第(2s)k+2(s−1)(2^{s})k+2^{(s-1)}(2s)k+2(s−1)移动的是s号盘,这时s号盘已被移动了k+1次.每2s2^s2s次就有一次是移动s号盘.
第一次移动s号盘是在第2(s−1)2^{(s-1)}2(s−1)次.
第二次移动s号盘是在第2s+2(s−1)2^s+2^{(s-1)}2s+2(s−1)次.
…
第k+1次移动s号盘是在第k∗2s+2(s−1)k*2^{s}+2^{(s-1)}k∗2s+2(s−1)次.1–2--3–1叫做顺时针方向,1–3--2–1叫做逆时针方向.
最大盘n号盘只移动一次:1–3,它是逆时针移动.
n-1移动2次:1–2--3,是顺时针移动.
如果n和k奇偶性相同,则k号盘按逆时针移动,否则顺时针.
#include<bits/stdc++.h>
using namespace std;
int main()
{int i, k;scanf("%d", &k);for (i = 0; i < k; i++){int n, l;__int64 m, j;__int64 s, t;scanf("%d%lld", &n, &m);s = 1;t = 2;for (l = 1; l <= n; l++){if (m % t == s)break;s = t;t *= 2;}printf("%d ", l);j = m / t;if (n % 2 == l % 2){ // 逆时针if ((j + 1) % 3 == 0)printf("2 1\n");if ((j + 1) % 3 == 1)printf("1 3\n");if ((j + 1) % 3 == 2)printf("3 2\n");}else{ // 逆时针if ((j + 1) % 3 == 0)printf("3 1\n");if ((j + 1) % 3 == 1)printf("1 2\n");if ((j + 1) % 3 == 2)printf("2 3\n");}}return 0;
}