《算法竞赛-训练指南》第一章-1.11——Uva 10795

来源:互联网 发布:维基百科 捐款 知乎 编辑:程序博客网 时间:2024/05/14 04:05

真有种想死的冲动,今天极其的没有效率啊。这个汉诺塔的问题一直都没有想通,现在也是模糊不清,主要是心理一直都不在这里。这能咋办?


但还是描述一题目:题目是这样一种新的汉诺塔,也是只有三个柱子,开始题目都没读懂,都不知道有几个盘子。然后是告诉你哪个柱子上起初有几个大小怎样的盘子,这里要弄清楚,是按照从大到小排列,不然的话,出这个题目一点都没意思,开始我还在纠结这个问题,我晕。然后有两种状态,第一种是最初的状态,第二种是最后的状态,问你经过最少的多少步能够走到最后的状态。


解题的思路:明显的做汉诺塔那就是递归的思路,将问题抽象成能够分类清楚并能解决最终问题的一个个子问题。最简单的汉诺塔是用3个盘子的移动过程,抽象出所有盘子的移动过程。而这道题目,就有些难度了。但其实汉诺塔的精髓还是怎么样从大到小的将所有的盘子都放到一个要求的柱子上,那么我们只有找到那个不符合要求的最大的盘子,放入它应该在的地方,这就是抽象出来的子问题。


因为,开始的时候所有的盘子可以不在一个地方,所有我们只能抽象出来这样一个方法,f(p,x,final)表示的意思是,将1-x所有的盘子都按顺序的装到了final这个柱子上。


然后就是有一个概念就是参考局面的概念,设置一个比较正规,不零散的局面,然前后两个状态分别走向这个状态,这样更容易求解。

即,很零散的初态(各个珠子上都有盘子),我们让它们规整的全部移动到一个柱子上,然后在从这种规整的状态走到很零散的末态,期间的步骤就是答案。汉诺塔只要你不重复的做无用功,即1->2,2->1。走出来的结果就一定是最优解的。


这个题目好是好,但给我的知识量并不大,原因就是自己太松散了。

贴出代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>using namespace std;const int MAXN = 66;int start[MAXN];int end[MAXN];int N;long long f(int *p, int x, int final)//这个函数表示的意义是,将x个盘子都移动到final上面需要的次数 {if (x == 0){return 0;}if (p[x] == final){return f(p, x - 1, final);}else{return f(p, x - 1, 6 - p[x] - final) + (1LL << (x - 1));} }int main(){int cas = 1;while (scanf("%d", &N) != EOF){if (N == 0){break;}for (int i = 1; i <= N; i++){scanf("%d", &start[i]);}for (int i = 1; i <= N; i++){scanf("%d", &end[i]);}int k = N;while (k >= 1 && start[k] == end[k]){k--;}if (k == 0){printf("Case %d: 0\n", cas++);continue;}int other = 6 - start[k] - end[k];long long ans = f(start, k - 1, other) + f(end, k - 1, other) + 1;printf("Case %d: %lld\n", cas++, ans);}//system("pause");return 0;}


原创粉丝点击