Uva 10795 A Different Task

汉诺塔问题的变形,给定初始局面和目标局面,问最少多少步可以把初始局面变成目标局面。

 

找到初始位置和目标位置不同的最大盘子X,那么比这个盘子还大的盘子就可以无视掉了。因为他们既不会被移动也不需要被移动。

 

我们设f(p[],x,final)为当前初始状态为p,要把比x小的盘子移动到柱子final的最少步数那么有f(p[],x,final)=f(p[],x-1,6-final-p[x])+2^(x-1)-1+1

意思就是先把比x-1小的都移动到柱子6-final-p[x],然后把x-1移动到final,然后把比x-1小的盘子移动到final

 

有了这个式子之后,我们要求的答案可以分解成,从开始局面开始,把比X小的盘子全部移动到中转位置,然后移动X,然后在移动到目标局面即可。最后移动到目标局面可以看成是从目标局面移动到中转位置,那么答案就是

ans=f(start[],X,6 – start[X] – final[X]) + f(final[],X,6 – start[X] – final[X]) + 1

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

typedef long long LL;
const int maxn = 70;
int start[maxn],finish[maxn];

LL f(int P[],int i,int fin) {
	if(i == 0) return 0;
	if(P[i] == fin) return f(P,i - 1,fin);
	return f(P,i - 1,6 - P[i] - fin) + 1 + (1LL << (i - 1)) - 1;
}

int main() {
	int n,kase = 1;
	while(scanf("%d",&n),n) {
		LL ans = 0LL;
		for(int i = 1;i <= n;i++) {
			scanf("%d",&start[i]);
		}
		for(int i = 1;i <= n;i++) {
			scanf("%d",&finish[i]);
		}
		for(int i = n;i >= 1;i--) if(start[i] != finish[i]) {
			ans = f(start,i - 1,6 - start[i] - finish[i]) + f(finish,i - 1,6 - start[i] - finish[i]) + 1;
			break;
		}
		cout << "Case " << kase << ": " << ans << endl;
		kase++;
	}
	return 0;
}

 

总结:汉诺塔类问题关键就是要找到一个会重叠出现的状态,然后写出递归式求解,中间也可以利用一些数学结论和技巧,比如可逆性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值