Description
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
后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
Sample Input
Sample Output
解题思路:
毕竟是和汉诺塔有关,所以这道题在处理的时候首要的还是要理解清楚汉诺塔的原理。
因为是已知的三个盘子的分布列和总盘子的个数。所以我们从n号盘子开始逆向往回判断每一个盘子的位置是否正确。直到找到一号盘子或者出现不正确的盘子位置。
因为在汉诺塔的解题思路是:第一步:将1~n-1 移到第二个盘子。第二步:把n移到第三个盘子。第三步:把1~n-1移到第三个盘子。
所以对于n个盘子的汉诺塔问题来说,第n个盘子只会出现在第一个盘子和最后一个盘子。
① n出现在第一个盘子时:n-1 只能处于第一个盘子(尚未移动)或者第二个盘子(等待n号盘子移动至第三个盘子)
② n出现在第三个盘子时:n-1 只能处于第二个盘子(等待从第二个盘子移动到三个盘子)或者第三个盘子(移动完毕)。
综上,进行判断即可判断出每一步的盘子出现的位置是否正确。
n = 4的时候汉诺塔的移动(如果不理解上面对于n-1位置的推测,可以分别看当n = 4时 3号的移动,n=3时 2号的移动):
1: move 1 disk from A to B.
2: move 2 disk from A to C.
3: move 1 disk from B to C.
4: move 3 disk from A to B.
5: move 1 disk from C to A.
6: move 2 disk from C to B.
7: move 1 disk from A to B.
8: move 4 disk from A to C.
9: move 1 disk from B to C.
10: move 2 disk from B to A.
11: move 1 disk from C to A.
12: move 3 disk from B to C.
13: move 1 disk from A to B.
14: move 2 disk from A to C.
15: move 1 disk from B to C.
这道题,因为自己在做的时候没做出来,看了老师的代码之后才做出来的。虽然代码是自己写的,但是和老师的代码可以说完全一样。
以下是AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define fn(i,n) for(int i = 0; i < n; i++)
const int maxn = 64;
int num[3][maxn];
int n[3],p[3];//这两个数组的0 1 2分别代表一二三号盘子,n数组是题目交代的各盘子上元素个数,p数组是盘子上已经确认位置正确的元素的位置
bool judge(int N, int fir, int sec, int thr){
if(p[fir] < n[fir] && num[fir][p[fir]] == N){
if(N == 1) return true;
p[fir]++;
return judge(N-1,fir,thr,sec);
}
else if(p[thr] < n[thr] && num[thr][p[thr]] == N){
if(N == 1) return true;
p[thr]++;
return judge(N-1,sec,fir,thr);
}
else return false;
}
int main(){
int T;
cin >> T;
while(T--){
int N, ans;
cin >> N;
fn(i,3){
cin >> n[i];
fn(j,n[i]) cin >> num[i][j];
}
memset(p,0,sizeof(p));
ans = judge(N,0,1,2);
if(ans) cout << "true" << endl;
else cout << "false" << endl;
}
}