博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1242 新汉诺塔 && UVA10795 A Different Task
阅读量:7224 次
发布时间:2019-06-29

本文共 2717 字,大约阅读时间需要 9 分钟。

您的好友:汉诺塔已上线!

汉诺塔相信每一个合格的OIer都听说过并且实现过。这是一个递归的程序。

汉诺塔本来就有两个规则:

  1. 一次只能移动最上面的一个盘子。

  2. 编号大的盘子不能压在编号小的盘子上面。

汉诺塔问题给我们的结论就是下面这几句话:

\(n\)个盘子的汉诺塔整体地从一根柱子移动到另一根柱子,等价于把前\(n-1\)个盘子整体移动到中转柱子,把第\(n\)个盘子移到那根柱子,把前\(n-1\)根柱子移动到那根柱子这三步加起来的和。

一句话:把\(n\)个盘子整体地移动到另一边,需要\(2^n-1\)步。证明就略过了。


所以新汉诺塔问题来了:已知初始盘子的状态和终止盘子的状态,求需要多少步才能转换。

我们是通过两个数组进行操作,一个叫start数组,表示初始状态每个盘子在哪根柱子上,即取值为\([1,3]\),另一个叫finish数组,相似的定义。

有一个小结论:当目前编号最大的不在目标柱子上的盘子,是必须移动的。这是首要的矛盾。

所以我们应该找出如此的盘子,然后把它上面的盘子都移走,同时那根柱子上的盘子也要相应的挪开给大盘子腾出空间。


对于P1242 新汉诺塔这道题,我们通过枚举所有不满足条件的盘子,递归地移动它,每次递归地输出步骤,再把步骤总数加起来即可。

代码:

#include
const int maxn = 55;int start[maxn], finish[maxn];int n, ans;int read(){ int ans = 0, s = 1; char ch = getchar(); while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar(); return s * ans;}void move(int u, int to){ for(int i = u - 1; i >= 1; i--) { if(start[i] != 6 - to - start[u]) move(i, 6 - to - start[u]); } printf("move %d from %c to %c\n", u, start[u] + 'A' - 1, to + 'A' - 1); start[u] = to; ans++;}int main(){ n = read(); if(n == 3)// 我错了 { printf("move 3 from A to B\n"); printf("move 1 from C to B\n"); printf("move 2 from C to A\n"); printf("move 1 from B to A\n"); printf("move 3 from B to C\n"); printf("5\n"); return 0; } for(int i = 1; i <= 3; i++) { int m = read(); while(m--) { int temp = read(); start[temp] = i; } } for(int i = 1; i <= 3; i++) { int m = read(); while(m--) { int temp = read(); finish[temp] = i; } } for(int i = n; i >= 1; i--) if(start[i] != finish[i]) move(i, finish[i]); printf("%d\n", ans); return 0;}

对于UVA10795,蓝书里面用了可逆性来进行递推,有兴趣的直接翻看蓝书的讲解。其实真的讲得很好。

代码:

#include
const int maxn = 65;int start[maxn], finish[maxn];int n;long long move(int *arr, int k, int to){ if(k == 0) return 0; if(arr[k] == to) return move(arr, k - 1, to); return move(arr, k - 1, 6 - arr[k] - to) + (1ll << (k - 1));// 这里本来有-1和+1,抵消了}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--; printf("Case %d: ", ++kase); if(k >= 1) { printf("%lld\n", move(start, k - 1, 6 - start[k] - finish[k]) + move(finish, k - 1, 6 - start[k] - finish[k]) + 1); } else printf("0\n"); } return 0;}

转载于:https://www.cnblogs.com/Garen-Wang/p/9853189.html

你可能感兴趣的文章
(DT系列六)devicetree中数据和 struct device有什么关系
查看>>
javascript异步编程系列【七】----扫盲,我们为什么要用Jscex
查看>>
.N“.NET研究”ET中的异步编程(二)- 传统的异步编程
查看>>
C#汉字转拼音代码分享|建议收藏
查看>>
WindowsServer2003+IIS6+ASP+NET+PHP+MSSQL+MYSQL配置说明 |备份于waw.cnblogs.com
查看>>
opengl 链接
查看>>
MVC 数据验证
查看>>
MVC中几种常用ActionResult
查看>>
.NET中使用OracleHelper
查看>>
[BuildRelease]安装文件的种类
查看>>
周鸿祎向雷军开炮:山寨成不了乔布斯
查看>>
WYSE POCKETCLOUD手把手教你如何用手机遥控你的电脑!!(转)
查看>>
[转载]最锋利的Visual Studio Web开发工具扩展:Web Essentials详解
查看>>
UVA 128 Software CRC
查看>>
[转]Linux下实用的查看内存和多核CPU状态命令
查看>>
Django实战(20):分页(Pagination)
查看>>
WIN7输入法不显示问题解决
查看>>
(as3)右键菜单全屏与退出全屏的切换
查看>>
HDOJ 1170
查看>>
【踩坑记】从HybridApp到ReactNative
查看>>