HDU 1997 汉诺塔Ⅶ

 汉诺塔VII
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64d

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 



是正确的 
例2:n=3 



是不正确的。 
注:对于例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号盘子开始逆向往回判断每一个盘子的位置是否正确。直到找到一号盘子或者出现不正确的盘子位置。

因为在汉诺塔的解题思路是:第一步:将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;
    }
}


发布了31 篇原创文章 · 获赞 0 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章