uva 10795 新汉诺塔问题
来源:互联网 发布:李涛淘宝 编辑:程序博客网 时间:2024/06/06 21:56
题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1736
有n个大小不一样的盘子和3个柱子。给定一个初始局面,求到给定目标局面至少需要多少步。
移动规则:一次只能移一个盘子,在移动一个盘子之前,必须把压在上面的其他盘子先移走,编号大的盘子不得压在编号小的盘子上。
这道题目需要一点想象空间啊确实,给出图片方便想象:
分析:
1.考虑编号最大的盘子,如果它在初始局面和目标局面位于同一个柱子,那么不需要移动它。
这样我们在初始局面和目标局面中,找到所在柱子不同的编号最大的那个盘子,设为k(下面用到的k都是同样的意思),k必须移动。
在题目图片中,如果上面是初始局面下面是目标局面的话,k=3;调换过来的话,k。。还是3。
2.在k移动前。假设k需要从柱子A移动到柱子B,由于编号比k大的盘子不需要移动,所以直接当作他们不存在。
编号比k小的既不能在A上,也不能在B上,所以只能在C上。
这时候,A只有盘子k,B没有盘子(比k大的不算),C从上到下依次是盘子1,2,3…k-1。
我们把这个局面称作参考局面。
3.由于盘子移动是可逆的,根据对称性,我们只需要求出初始局面和目标局面移动成参考局面的步数之和,然后加1(移动盘子k)即可。
注意,这里初始到参考的参考局面和目标到参考的参考局面是不一样的。如果初始到参考的参考局面是k从柱子A到B,那么目标到参考的参考局面就是k从柱子B到A。(拿个例子看看就知道了)
然后我们需要写一个函数f(P,i,final),P是各盘子初始局面的柱子编号数组(P[i]是盘子i的柱子编号),函数的值是将i个盘子移动柱子final的所需步数。
那么本题答案:f(start,k-1,6-start[k]-final[k]) + f(final,k-1,6-start[k]-final[k]) + 1 其中start[i]和final[i]就是i盘子的初始柱子和目标柱子,k就是要移动的盘子的最大编号。
因为柱子编号为1,2,3,所以剩下的那个柱子编号就是6-start[k]-final[k]。
4.接下来要计算f(P,i,final)。
(1)如果P[i] = final ( 意思是该移动的编号i已经在柱子final上),那么f(P,i,final)=f(P,i-1,final)。
(2)如果P[i] ≠ final,那么需要把前i-1个盘子移动到6-P[i]-final这个柱子作为中转,然后把i移动到柱子final上,最后在把i-1个盘子移动到柱子final上。
最后一步是把i-1个盘子从一个柱子移到另一个柱子上(旧汉诺塔问题),这个步骤需要 (2∧i-1)-1 步(如将3个盘子从A移到B,需要7步)。加上移动盘子i的那一步,就是2∧i-1。
那么答案就是 f(P,i,final) = f(P,i-1,6-p[i]-final) + 2∧i-1。
5.最后答案要用long long保存。因为int是32位,n<=60。2∧i-1会超。
6.然后贴一个旧汉诺塔问题的链接:
http://blog.csdn.net/liujian20150808/article/details/50793101
#include<cstdio>long long f(int *P, int i, int final){ if (i == 0) return 0; if (P[i] == final) return f(P, i - 1, final); return f(P, i - 1, 6 - P[i] - final) + (1LL << (i - 1));}const int maxn = 60 + 10;int n, start[maxn], finish[maxn];int main(){ int kase = 0; while (scanf("%d", &n) == 1 && 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 >= 1 && start[k] == finish[k]) k--; long long 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", ++kase, ans); } return 0;}
- UVA - 10795(新汉诺塔问题)
- uva 10795 新汉诺塔问题
- UVa 10795 A Diffenent Task 新汉诺塔问题
- UVA 10795 A Different Task(新汉诺塔问题)
- 汉诺塔相关,递归(新汉诺塔问题,uva 10795)
- RMQ问题 UVa 11235
- UVA 11235 RMQ问题
- uva 10465(背包问题)
- UVA(木块问题)101
- uva--10057+数学问题
- UVA - 11300(问题转换)
- UVA 埃及分数问题
- UVa 1393 问题抽象
- Uva 倒水问题
- 101UVa木块问题
- uva 10603 倒水问题
- 油田问题 UVA 572
- 油田问题 UVA 572
- 深入浅出FPGA-14-ChipScope软件使用
- Python轻松入门-07 if elif else
- Leap Motion开发环境配置LeapmotionDevelopmentKit3.2.0+VS2013
- normal map compression & tangent to world space conversion
- uva 11210 麻将
- uva 10795 新汉诺塔问题
- 计算机图形学的一些算法
- 将 ext_net 连接到 router - 每天5分钟玩转 OpenStack(145)
- 解析漏洞总结
- 精简指令集计算机
- cursor row 的使用方法 第九章
- cf682b
- RISC-V的开源性与用途
- 纪念品分组