汉诺塔VII
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1568 Accepted Submission(s): 1033
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盘. 则是正确的.
后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,
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
true false false false true true
递推的思维,从第n个盘子开始,即假设n刚刚移动到某一个位置,推出接下来要移动的盘子。
ps:n个盘子要从1号柱子移到3号柱子,第n个盘子不可能出现在2号柱子。
若n在1号柱子上,再判断第n-1个盘子在哪个柱子,若n-1在1号柱子,说明尚在移动前n-2个盘子,还未移动到n和n-1,递归返回判断n-2,
由于前n-2个盘子也是要从1号柱子移到3号柱子,a1,a2,a3顺序不变;若n-1在2号柱子,说明前n-2个刚刚全部移动到3号柱子,
接下来要把前n-2个柱子移动到2号
柱子,从3号柱子移动到2号柱子,交换顺序,a3, a1, a2;若n-1在3号柱子上说明移错了.......接下来同理.....
#include<cstdio>
int pos[100];
int hanoi(int n, int a1, int a2, int a3){
if(n <= 0 || (n == 1 && pos[n] != a2)){
return 1;
}
if(pos[n] == a1){
if(pos[n-1] == a1){
return hanoi(n - 2, a1, a2, a3);
}
if(pos[n-1] == a2){
return hanoi(n - 2, a3, a1, a2);
}
return 0;
}
if(pos[n] == a3){
if(pos[n-1] == a2){
return hanoi(n - 2, a2, a3, a1);
}
if(pos[n-1] == a3){
return hanoi(n - 2, a1, a2, a3);
}
return 0;
}
return 0;
}
int main(){
int x, m, n, t;
scanf("%d", &x);
while(x--){
scanf("%d", &m);
for(int i = 1; i <= 3; i++){
scanf("%d", &n);
for(int j = 0; j < n; j++){
scanf("%d", &t);
pos[t] = i;
}
}
printf(hanoi(m, 1, 2, 3) ? "true\n" : "false\n");
}
return 0;
}
后来看同学有更简单的,更好理解一点,上面的虽然能懂但是复杂多了-----------
三个盘子1,2,3;一个盘子x要从1移动到3,就不能出现在2上,否则移动次数不是最少的,对于本题来说就是错误的,很容易证明
举3个盘子的例子自己也能很容易推出来
轮到移动某一个盘子n时,n所在柱子设为起点(sta),目标柱子设为终点(end),另外一个设为中点(mid),则n只能出现在
起点和终点,出现在中点就是错误。例如n是最大的盘子,要从1号柱子移动到3号柱子,起点为1号柱子,终点为3号柱子,n只能
出现在1号柱子或3号柱子,出现在1号柱子(即起点)说明第n-1个盘子正在从1号柱子移向2号柱子,则递归到n-1时,起点和终
点变成了1号柱子和2号柱子;n在3号柱子时,说明第n-1个柱子正在从2号柱子移动到3号柱子,递归到n-1时,起点和终点变成了
2号柱子和3号柱子。
原理有了,代码就好写了,依次递归就可以
#include<cstdio>
int pos[100];
int hanoi(int n, int sta, int end, int mid){
if(pos[n] == 0){
return 1;
}
if(pos[n] == mid){
return 0;
}
if(pos[n] == sta){
return hanoi(n - 1, sta, mid, end);//n的位置在起点,n-1起点终点位置变化
}
if(pos[n] == end){
return hanoi(n - 1, end, mid, sta);//n的位置在终点,n-1起点终点位置也依据上述原理做相应变化
}
}
int main(){
int t, m, n, k;
scanf("%d", &t);
while(t--){
scanf("%d", &m);
for(int i = 1; i <= 3; i++){
scanf("%d", &n);
for(int j = 0; j < n; j++){
scanf("%d", &k);
pos[k] = i;
}
}
printf(hanoi(m, 1, 3, 2) ? "true\n" : "false\n");
}
return 0;
}