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盤. 則是正確的.
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,
後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個圓盤與其他n-1個圓盤分開看。首先,將其他n-1個圓盤移到B圓盤,再把第n個圓盤移到C圓盤,最後將在B上的那n-1個圓盤集體移到C上就完成了整個過程。在這裏給大家張貼一段代碼,這個代碼也是最簡單的漢諾塔問題,即,如何將n個圓盤從最左邊的A杆移動到左右側的C杆,需要經歷怎樣的步驟,代碼如下:
//Hanoi Problem
#include<iostream>
using namespace std;
void Hanoi(int n,char A,char B,char C)
{
if(1==n) ///如果A上只剩下1個圓盤的時候,直接把這個圓盤從A移到C即可
{
cout<<"從"<<A<<"移到"<<C<<endl;
}
else
{
Hanoi(n-1,A,C,B);///先將另外n-1個圓盤從A藉助C移動到B
cout<<"從"<<A<<"移到"<<C<<endl;///第n個圓盤從A移到C
Hanoi(n-1,B,A,C);///再將n-1個圓盤從B藉助A移到C
}
}
int main()
{
Hanoi(3,'A','B','C');
return 0;
}
以上代碼的運行結果是(當然了,每次都是那對應杆上的最上面的那個圓盤):而本題是這個問題的一個延伸,用的是深度優先搜索的方法,還有一些分治的思想。我們還是要從最下面的那個第n個圓盤入手,當你想將n個圓盤從A圓盤移動到C圓盤的時候,你得先將另外n-1個圓盤移動到B,再把A移動到C,這是最簡單的方式。因此,你肯定不能將第n個圓盤移動到B圓盤上,否則,就這道題而言就是不正確的。那另外兩種情況呢?
首先是第n個圓盤再A杆上,此時就是之前說的:其他n-1個圓盤移到B圓盤,再把第n個圓盤移到C圓盤,最後將在B上的那n-1個圓盤集體移到C上。
要是第n個圓盤再C上的話,你只需將另外在n-1個圓盤直接移到C上即可。
相關解釋,在代碼中已經給出瞭解釋:
#include<iostream>
using namespace std;
bool DFS(int n,int A[],int B[],int C[])///將n個圓盤從A杆藉助B杆從而移到C杆
{
if(B[0]==n)///如果第n個盤在B杆上的話,就多步驟了,這是不正確的
{
return false;
}
else if(A[0]==n) ///如果第n個圓盤在A杆上
{
return DFS(n-1,A+1,C,B);///將第n個圓盤上方(所以是A+1)的n-1個圓盤藉助C移到B上
}
else if(C[0]==n) ///如果第n個圓盤在C杆上
{
return DFS(n-1,B,A,C+1);///將B上的n-1個圓盤藉助A移到C杆上,且在第n個圓盤的上方(所以是C+1)
}
return true;
}
int main()
{
int A[70],B[70],C[70];
int testNum;
int n,m,p,q;
cin>>testNum;
while(testNum--)
{
cin>>n;
cin>>m;
for(int i=0;i<m;i++)
{
cin>>A[i];
}
cin>>p;
for(int i=0;i<p;i++)
{
cin>>B[i];
}
cin>>q;
for(int i=0;i<q;i++)
{
cin>>C[i];
}
if(DFS(n,A,B,C))
{
cout<<"true"<<endl;
}
else
{
cout<<"false"<<endl;
}
}
return 0;
}