例题1.11 新汉诺塔问题 UVa10795

该博客详细介绍了如何解决一个汉诺塔问题的变形题,涉及递推公式和动态规划策略。通过定义参考状态和函数f(P,i,final),解释了如何计算从初始状态到目标状态的最小移动步数,强调了计算过程中避免错误增加步数的细节,并提到由于问题规模大,需要使用long long类型存储结果。" 120873359,11052592,Java集合实现学生信息管理系统,"['Java', 'eclipse', '集合框架']
摘要由CSDN通过智能技术生成

1.题目描述:点击打开链接

2.解题思路:本题是经典汉诺塔问题的变形题,根据解汉诺塔问题时的思路,我们试着找递推公式来解决本题。考虑最大的盘子,设它为k,如果此时它不在目标柱子上,说明它必须移动。现在,我们定义一种参考状态:最大的盘子k在柱子1,柱子2为空,柱子3从上到下依次是1,2……k-1。根据问题的可逆性,我们只需要求出初始局面和目标局面移动成参考局面的步数之和,然后加1(移动盘子k到目标柱子)。这里我们定义一个函数f(P,i,final),表示把盘子1,2……i移到柱子final所需的步数(P[i]中保存的是盘子i的柱子编号)。根据上述想法,本题的最终答案就是f(start,k-1,6-start[k]-finish[k])+f(finish,k-1,6-start[k]-finish[k])+1。这里我们把柱子编号为了1,2,3,因此“除了柱子x,柱子y之外的柱子”就是6-x-y。注意:不要误以为需要加两次1!

那么如何计算f(P,i,final)函数呢?若P[i]==final,那么答案就是f(P,i-1,final);否则,先将前i-1个盘子移动到柱子6-P[i]-final作为中转,然后把盘子i移动到柱子final,最后把前i-1个盘子移动到final。根据汉诺塔问题的结论,把前i-1个盘子从中转柱子移动到final的步数是2^(i-1)-1步,再加上移动盘子i到final这一步,总共是2^(i-1)步。因此,当P[i]!=final时,答案是f(P,i-1,6-P[i]-final)+2^(i-1)。由于n高达60,因此需要用long long保存结果。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long LL;
#define N 60+10
int n, start[N], finish[N];
LL f(int*P, int i, int final)//表示将盘子1,2……i移到柱子final所需要的步数
{
	if (!i)return 0;
	if (P[i] == final)return f(P, i - 1, final);//最后一个盘子i恰好在柱子final
	return f(P, i - 1, 6 - P[i] - final) + (1LL << (i - 1));//先将前i-1个盘子移到柱子6-P[i]-final作为中转,然后把盘子i移到柱子final,最后把前i-1个盘子移到final
}
int main()
{
	//freopen("t.txt", "r", stdin);
	int rnd = 0;
	while (~scanf("%d", &n) && n)
	{
		for (int i = 1; i <= n; i++)cin >> start[i];
		for (int i = 1; i <= n; i++)cin >> finish[i];
		int k = n;
		while (k >= 1 && start[k] == finish[k])k--;

		LL ans = 0;
		if (k >= 1)
		{
			int other = 6 - start[k] - finish[k];
			ans = f(start, k - 1, other) + f(finish, k - 1, other) + 1;
		}
		printf("Case %d: %lld\n", ++rnd, ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值