uva10795(汉莫塔)

题意:
给出碟子的数量,
然后给出一开始碟子的位置,和最终碟子的位置,问最少移动几次可以完成,要求和普通汉诺塔一样,大的不能叠在小的上面;


思路:
感觉没看题解完全想不出来这个思路;
大体思路就是,你要把最大的盘子从1移到2,那么在这个盘子上面的盘子,还有2上所有的盘子,都要先移到3;然后在移回来;
旧汉诺塔:将A柱子上的n个盘子,移到B柱子上


旧汉诺塔 f(n)=f(n-1)+1+f(n-1)=(2^n)-1;f(1)=1;


首先需要把编号最大的盘子N移到目标柱子上,于是需要有这样的局面:假设N需要从A移到B,A只有N,B是空的,C上面是N-1到1,因此需要将N-1移到C,然后将N移到B,最后将N-1移到B。因此f(n)=2*f(n-1)+1;

 新汉诺塔问题:首先找最大不在目标柱子上的盘子K,因为如果最大的盘子在目标柱子上它不需要移动,也不碍事。


 因此问题就成了把K移动到目标柱子,把1到(k-1)移动到中转柱子,所以假设K从A移动到B,A只有K,B是空的,C上面是K-1到1,把这个局面称为参考局面。因为移动是对称的,所以从参考局面移到目标局面与目标局面移到参考局面是一样的步数。

 所以问题变成答案=从初始局面移到参考局面步数+目标局面移到参考局面步数+1;

 需要写一个函数f(P,i,final),表示已知个盘子的初始柱面编号数组为P,把1到i移动到final的步数,本题答案是f(start,k-1,6-start[k]-finish[k])+f(finish,k-1,6-start[k]-finish[k])+1;

 计算f(P,i,final),若p[i]=final,则f(P,i,final)=f(P,i-1,final);否则需要把前i-1个盘子挪到中转盘去,将盘子i移到柱子final去,做后把前i-1个盘子从中转盘移到柱子final.。最后一步是把i-1个盘子从一个柱子移到另一个柱子,根据旧汉诺塔问题,这个步骤需要2^(i-1)-1步,加上移动盘子i那一步,一共需要2^(i-1)步。


 f(P,i,final)=f(P,i-1,6-p[i]-final)+2^(i-1);



#include<cstdio>
#include<cstring>

#define ll long long
const int N = 65;
int n,start[N],finish[N];

ll fun(int* p , int i ,int f) {
	if(i == 0)
		return 0;
	if(p[i] == f)
		return fun(p , i - 1 ,f);
	return fun(p , i - 1 ,6 - p[i] -f) +((ll)1 << (i - 1));
}
int main() {
	int cas = 1;
	while(scanf("%d",&n) && n) {
		for(int i = 1 ; i <= n ; i++) {
			scanf("%d",&start[i]);
		}
		for(int i = 1 ; i <= n ; i++) {
			scanf("%d",&finish[i]);
		}
		int k = n;
		while(k > 0 && start[k] == finish[k])
			k--;
		ll ans = 0;
		if(k > 0) {
			int other = 6 - start[k] - finish[k];
			ans = fun(start , k - 1 ,other) + fun(finish ,k - 1,other) + 1;
		}
		printf("Case %d: %lld\n",cas++ , ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值