新版汉诺塔(UVa10795 - A Different Task)
2015-06-11 17:31
316 查看
题目介绍:
标准的汉诺塔上有n个大小各异的盘子。现给定一个初始局面(见图1),求它到目标局面(见图2)至少需要移动多少步?移动规则:一次只能移动一个盘子;且在移动盘子之前,必须把压在上面的其他盘子先移走;基于汉诺塔问题的原始约定,编号大的盘子不得压在编号小的盘子上。
Sample Input
3
1 1 1
2 2 2
3
1 2 3
3 2 1
4
1 1 1 1
1 1 1 1
0
Sample Output
Case 1: 7
Case 2: 3
Case 3: 0
问题分析:
为了更好的剖析问题。我们首先考虑编号最大的盘子。显然,如果这个盘子的在初始局面和目标局面中位于同一根柱子,那么我们可以根本不需要移动它。直接忽略它在两个局面的存在。设现在存在初始局面跟目标局面中位置不同的盘子最大编号为k。现在设想一下移动k之前的瞬间。不妨假设盘子k需要从柱子A移动到柱子B,那么在移动k之前的局面必然是,1,2,...k-1全部位于柱子C,而且从上到下排好序。我们把这个局面称为参考局面。
根据对称性,我们只需要求出初始局面和目标局面到参考局面移动的步数之和,再加上1(移动编号为k的盘子)即可。
现定义这样的一个函数 f(arr,k,flag):表示已知各盘子的初始编号为数组arr,把1,2,...,k移动到flag柱子所需要的最少步数。可得本题答案表示如下:
ans = f(start,k-1,6-start[k]-finish[kl) + f(finish,k-1,6-start[k]-finish[kl) + 1;
将问题分解之后,我们再考虑如何基于汉诺塔的性质,递归求解f(arr,k,flag)。
显然,k=0时意味着没有盘子需要移动,此时返回0,作为递归跳出的判断条件;
K!=0时,比较arr[k]==flag? 如果相等,那么很好办,直接f(arr,k,flag) = f(arr,k-1,flag)即可,因为编号k不需要移动。当arr[k]!=flag时就需要推导一下了。我们把“1,2,...,k-1”看做一个整体,此时移动k前后需要将整体从一个柱子移动到另一个柱子,而根据汉诺塔的经典理论,将n个盘子初始有序的盘子由一个柱子移动到另一个柱子最少需要:2^n - 1 次。本题中,我们还要加上移动盘子k的一次操作,故最后:
f(arr,k,flag) = f(arr,k-1,6-arr[k]-flag) + (1<<(k-1))
参考代码:
#include <cstdio> typedef long long ll; const int maxn=64; int a[maxn],b[maxn]; ll f(int *a,int k,int flag){ if(k<1) return 0; else if(a[k]==flag){ return f(a,k-1,flag); }else{ return f(a,k-1,6-a[k]-flag) + (1LL<<(k-1)); //"1LL"自动转换为long long 类型 } } int main(){ int n,t=1; while(scanf("%d",&n)==1 && n){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); //find 'k' int k=n; while(a[k]==b[k] && k>=1)k--; ll ans=0; ans = f(a,k-1,6-a[k]-b[k]) + f(b,k-1,6-a[k]-b[k]) + 1; if(k==0) ans = 0; printf("Case %d: %lld\n",t++,ans); } return 0; }
结语:
这道题从刚开始入手的杂乱通过一步步转换推导之后,最终程序的精简实现不由得让人拍案叫绝!本文解析或许词不达意,不到之处请谅解。同时,欢迎有其他思路或想法的朋友私下交流讨论。
(hint:提交本题目时注意数据类型选用64位整型数long long,”(1<<(k-1))”若没有加上“LL”则提交结果为WA! )
相关文章推荐
- 学习老外用webstorm开发nodejs的技巧--代码提示DefinitelyTyped
- php+jquery+ajax+json简单小例子
- jQuery选择器全面总结
- 关于闭包
- 样式与主题
- jQuery时间验证和转换为标准格式的时间
- HTML5学习笔记 Web存储
- css元素居中实现方法
- innerHTML对比DOM方法,哪个性能好?有什么区别?
- js 的try catch应用
- Windows Phone 三、样式和资源
- 复选框批量处理前端实现
- 【LeetCode】25.Reverse Nodes in k-Group
- ndis6.0 NetBufferSend
- 【迁移学习】2010-A Survey on Transfer Learning
- TIKZ全局样式设置
- 对js闭包的学习
- html 字符串拼接
- JS常用代码备忘
- HTML5新特性展示利用history.replaceState()修改历史记录