[JZOJ2136] 汉诺塔
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步,编程求在某步数时的状态。
现在再加上一个条件:不允许直接把盘从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
输入文件的第一行为整数T(1<=T<=50000),表示输入数据的组数。
接下来T行,每行有两个整数N,M(1<=n<=19,0<=M<=移动N个圆盘所需的步数)。
接下来T行,每行有两个整数N,M(1<=n<=19,0<=M<=移动N个圆盘所需的步数)。
Output
输出文件有T行。
对于每组输入数据,输出N个整数表示移动N个盘在M步时的状态,每两个数之间用一个空格隔开,行首和行末不要有多余的空格。
对于每组输入数据,输出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
Summary
找规律,手推N=3时的所有状态,第一位是1,2,3,3,2,1......第二位是1,1,1,2,2,2,3,3,3,3,3,3,2,2,2,1,1,1......以此类推。
Code
1 #include<cstdio> 2 using namespace std; 3 int t,x,y,a[20]; 4 int main() 5 { 6 scanf("%d",&t); 7 for (int i=1;i<=t;i++) 8 { 9 scanf("%d%d",&x,&y); 10 y++; 11 int p=6,k=1; 12 for (int i=1;i<=x;i++) 13 { 14 int sum=y%p,j=1; 15 bool f=true; 16 while (sum>k) 17 { 18 if (j==3) 19 { 20 f=not f; 21 j=1; 22 } 23 else j++; 24 sum=sum-k; 25 } 26 p=p*3; 27 k=k*3; 28 if (f) a[i]=j; 29 else a[i]=4-j; 30 } 31 for (int j=1;j<=x-1;j++) 32 printf("%d ",a[j]); 33 printf("%d\n",a[x]); 34 } 35 }