【UVA】10795 A Different Task-汉诺塔&递归

本文探讨了汉诺塔问题的最优解策略,通过锁定编号最大的盘子并将其移动到目标柱子上的方法,避免了不必要的移动。文章详细解释了如何通过递归函数F计算最小移动步数,并提供了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题解

首先锁定编号最大的盘子,若它就在目标柱子上,则不移动它是最优的。而将其移动到目标柱子后,剩下的编号更小的盘子之间的移动不会受任何影响。所以每次先将编号最大的盘子(假设为xxx)移到目标柱子上。

xxx初始位于ststst柱子上,目标柱子为ededed,将xxxststst移动到ededed时,1,2,...,x−11,2,...,x-11,2,...,x1号盘子必然不在st/edst/edst/ed上,所以还需要提前把1,2,...,x−11,2,...,x-11,2,...,x1整体移动到6−st−ed6-st-ed6sted上(盘子编号分别为1,2,31,2,31,2,3)。

移动盘子的过程可逆,所以答案即为:将初始状态移动到上述局面的步数+目标状态移动到上述局面的步数+1。设函数F(p,x,fl)F(p,x,fl)F(p,x,fl)(ppp数组表示当前局面各盘子初始在的柱子编号,将1,2,...,x1,2,...,x1,2,...,x移动到目标柱子flflfl的步数)。
ans=F(st,x−1,6−stx−edx)+F(ed,x−1,6−stx−edx)+1ans=F(st,x-1,6-st_x-ed_x)+F(ed,x-1,6-st_x-ed_x)+1ans=F(st,x1,6stxedx)+F(ed,x1,6stxedx)+1

对于F(st,x,fl)F(st,x,fl)F(st,x,fl)stx=flst_x=flstx=fl时,F(st,x,fl)=F(st,x−1,fl)F(st,x,fl)=F(st,x-1,fl)F(st,x,fl)=F(st,x1,fl),否则F(st,x,fl)=F(st,x−1,6−stx−flx)+2x−1F(st,x,fl)=F(st,x-1,6-st_x-fl_x)+2^{x-1}F(st,x,fl)=F(st,x1,6stxflx)+2x1
1,2,...,x−11,2,...,x-11,2,...,x1整体移动到6−stx−flx6-st_x-fl_x6stxflx后又整体移回flflfl,根据汉诺塔问题的结论,移动步数为2x−1−12^{x-1}-12x11


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans;
int n,st[70],ed[70];

ll F(int *p,int x,int fl)
{
	if(!x) return 0;
	if(p[x]==fl) return F(p,x-1,fl);
	return F(p,x-1,6-p[x]-fl)+(1LL<<(x-1));
}

int main(){
	int i,j;
	for(j=1;;++j){
		scanf("%d",&n);if(!n) break;
		for(i=1;i<=n;++i) scanf("%d",&st[i]);
		for(i=1;i<=n;++i) scanf("%d",&ed[i]);
		for(;n && st[n]==ed[n];--n);ans=0;
		if(n) ans=F(st,n-1,6-st[n]-ed[n])+F(ed,n-1,6-st[n]-ed[n])+1;
		printf("Case %d: %lld\n",j,ans);
	}
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值