[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步,编程求在某步数时的状态。

Input

  输入文件的第一行为整数T(1<=T<=50000),表示输入数据的组数。
  接下来T行,每行有两个整数N,M(1<=n<=19,0<=M<=移动N个圆盘所需的步数)。

Output

  输出文件有T行。
  对于每组输入数据,输出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 }
View Code

 

posted @ 2018-07-16 10:17  kasiruto  阅读(62)  评论(0编辑  收藏