HDOJ-----1997汉诺塔VII-----数学思维题

汉诺塔VII

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1568    Accepted Submission(s): 1033


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个盘子开始,即假设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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值