题目:
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
)
=
(
2
n
)
−
1
f(n)=(2^n)-1
f(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号盘.
第
(
2
s
)
k
+
2
(
s
−
1
)
(2^{s})k+2^{(s-1)}
(2s)k+2(s−1)移动的是s号盘,这时s号盘已被移动了k+1次.每
2
s
2^s
2s次就有一次是移动s号盘.
第一次移动s号盘是在第
2
(
s
−
1
)
2^{(s-1)}
2(s−1)次.
第二次移动s号盘是在第
2
s
+
2
(
s
−
1
)
2^s+2^{(s-1)}
2s+2(s−1)次.
…
第k+1次移动s号盘是在第
k
∗
2
s
+
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;
}