汉诺塔VII(递推,模拟)
汉诺塔VII |
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) |
Total Submission(s): 1503 Accepted Submission(s): 1077 |
Problem Description
n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列。由于发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上,即各柱子从下往上的大小仍保持如下关系 :
n=m+p+q a1>a2>...>am b1>b2>...>bp c1>c2>...>cq ai是A柱上的盘的盘号系列,bi是B柱上的盘的盘号系列, ci是C柱上的盘的盘号系列,最初目标是将A柱上的n个盘子移到C盘. 给出1个系列,判断它是否是在正确的移动中产生的系列. 例1:n=3 3 2 1 是正确的 例2:n=3 3 1 2 是不正确的。 注:对于例2如果目标是将A柱上的n个盘子移到B盘. 则是正确的. |
Input
包含多组数据,首先输入T,表示有T组数据.每组数据4行,第1行N是盘子的数目N<=64.
后3行如下 m a1 a2 ...am p b1 b2 ...bp q c1 c2 ...cq N=m+p+q,0<=m<=N,0<=p<=N,0<=q<=N, |
Output
对于每组数据,判断它是否是在正确的移动中产生的系列.正确输出true,否则false |
Sample Input
6 3 1 3 1 2 1 1 3 1 3 1 1 1 2 6 3 6 5 4 1 1 2 3 2 6 3 6 5 4 2 3 2 1 1 3 1 3 1 2 1 1 20 2 20 17 2 19 18 16 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 |
Sample Output
true false false false true true
|
题解:借助人家的代码,方法是找第n个盘子要在A盘或者C盘;
下面是人家的思路:
①考虑最大盘子 n 号盘子,移动方向为A——>C,它只能在A或者C上,如果它在B上,则为false;
②如果 n 号盘子在 A 上,则其上的 n-1 号盘子必处于从A——>B的移动过程中,此时最大盘号为 n-1,移动方向为A—>B;
③如果 n 号盘子在 C 上,则其上的 n-1 号盘子必处于从B——>C的移动过程中,此时最大盘号为 n-1,移动方向为B—>C;
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<string> using namespace std; const int INF=0x3f3f3f3f; #define mem(x) memset(x,0,sizeof(x)) #define SI(x) scanf("%d",&x) #define PI(x) printf("%d",x) #define SL(x) scanf("%lld",&x) #define P_ printf(" ") #define T_T while(T--) const int MAXN=70; int a[4][MAXN]; bool work(int n,int m,int p,int q){ //最大的盘子一定在A盘或者c盘上; if(n==0)return true; //PI(n); if(a[m][a[m][0]]==n){ a[m][0]--; return work(n-1,m,q,p); } if(a[q][a[q][0]]==n){ a[q][0]--; return work(n-1,p,m,q); } return false; } int main(){ int n,m,p,q,T; SI(T); T_T{ SI(n); SI(a[1][0]); for(int i=a[1][0];i>=1;i--)SI(a[1][i]); SI(a[2][0]); for(int i=a[2][0];i>=1;i--)SI(a[2][i]); SI(a[3][0]); for(int i=a[3][0];i>=1;i--)SI(a[3][i]); if(work(n,1,2,3))puts("true"); else puts("false"); } return 0; }