原题:
http://172.16.0.132/junior/#contest/show/1373/1
题目描述:
古老的汉诺塔问题是这样的:用最少的步数将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步,编程求在某步数时的状态。
输入:
输入文件的第一行为整数T(1<=T<=50000),表示输入数据的组数。
接下来T行,每行有两个整数N,M(1<=n<=19,0<=M<=移动N个圆盘所需的步数)。
输出:
输出文件有T行。
对于每组输入数据,输出N个整数表示移动N个盘在M步时的状态,每两个数之间用一个空格隔开,行首和行末不要有多余的空格
样例输入:
4
2 0
2 5
3 0
3 1
样例输出:
1 1
1 2
1 1 1
2 1 1
分析:
本题仍然可以使用经典汉诺塔问题的算法来解决。
在经典汉诺塔问题中,算法分为3步:
1、将最小的n-1个盘从a移到b
2、将最大的第n个盘从a移到c
3、将最小的n-1个盘从b移到c
递归方程 f[n]=f[n-1]+1+f[n-1]
而,新的汉诺塔问题由于新的限制,算法分为5步:
1、将最小的n-1个盘从a移到c
2、将最大的第n个盘从a移到b
3、将最小的n-1个盘从c移到a
4、将最大的第n个盘从b移到c
5、将最小的n-1个盘从a移到c
因此,新的递归方程f[n]=f[n-1]+1+f[n-1]+1+f[n-1];
实现:
var
f,ans:array[0..21]of int64;
i:longint;
t,m,n:int64;
procedure move(n,m,t1,t2,t3:int64);
begin
if n=0 then exit;
if m<=f[n-1] then
begin
ans[n]:=t1;
move(n-1,m,t1,t2,t3);
exit;
end;
if m<=f[n-1]+1+f[n-1] then
begin
ans[n]:=t2;
move(n-1,m-(f[n-1]+1),t3,t2,t1);
exit;
end;
ans[n]:=t3; move(n-1,m-(f[n-1]+1+f[n-1]+1),t1,t2,t3);
end;
begin
assign(input,'hanoi.in');reset(input);
assign(output,'hanoi.out');rewrite(output);
f[0]:=0;
for i:=1 to 19 do f[i]:=f[i-1]+1+f[i-1]+1+f[i-1];
readln(t);
while t>0 do
begin
readln(n,m);
move(n,m,1,2,3);
write(ans[1]);
for i:=2 to n do write(' ',ans[i]);
writeln;
dec(t);
end;
close(input);close(output);
end.