CF392B Tower of Hanoi
题目链接。
Description
三塔汉诺塔问题,给一个 \(3 \times 3\) 的矩阵 \(t\),\(t_{i, j}\) 表示从 \(i\) 塔移动一个盘子到 \(j\) 塔的花费。
初始状态 \(n\) 个盘子都在第一个盘子,要求将所有的移到第三个盘子,求最小花费。
Solution
显然可以间接移动,花费有可能更优,先用 Floyd 算法算出从 \(i\) 间接 / 直接移动到 \(j\) 的最小花费,设 \(d_{i,j}\) 表示从 \(i\) 到 \(j\) 的最小花费。
显然无后效性,考虑 \(dp\)。
状态设计
设 \(f_{i,a,b}\) 表示将 \(i\) 个盘子从 \(a\) 移动到 \(b\) 的最小花费。
初始状态
\(f_{1, a, b} = d_{a,b}\) 其余为正无穷
状态转移
不妨设另外一个盘子为 \(c\)。
先把 \(n\) 个盘子看做两个整体:第 \(n\) 个盘子和 \(n - 1\) 个盘子,这样可以 DP 了。
通过观察发现有两个可能成为最优的转移方式:
- 将 \(n - 1\) 个盘子 \(a \Rightarrow c\),第 \(n\) 个盘子 \(a \Rightarrow b\),然后再把 \(n - 1\) 个盘子 \(c \Rightarrow b\)。
- \(n - 1\) 个盘子 \(a \Rightarrow b\),第 \(n\) 个盘子 \(a \Rightarrow c\),\(n - 1\) 个盘子 \(b \Rightarrow a\),第 \(n\) 个盘子 \(c \Rightarrow b\),\(n - 1\) 个盘子 \(a \Rightarrow b\)。
其他的转移一定是这两种 + 反复横跳形成的。
将上面的方式翻译一下,即:
\(f_{i, a, b} \gets f_{i - 1, a,c} + t_{a,b} + f_{i - 1, c, b}\)
\(f_{i, a, b} \gets f_{i - 1, a,b} + t_{a,c} + f_{i - 1, b, a} + t_{c,b} + f_{i - 1, a, b}\)
值得注意的是这里不能用 \(d\),因为其他盘子不是空的,不能作为间接量。
时间复杂度
\(O(N)\)
Tips
注意开 long long !
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 45;
typedef long long LL;
int t[3][3], g[3][3], n;
LL f[N][3][3];
int main() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) scanf("%d", &t[i][j]), g[i][j] = t[i][j];
scanf("%d", &n);
for (int k = 0; k < 3; k++)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
t[i][j] = min(t[i][j], t[i][k] + t[k][j]);
memset(f, 0x3f, sizeof f);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
f[1][i][j] = t[i][j];
for (int i = 2; i <= n; i++) {
for (int a = 0; a < 3; a++) {
for (int b = 0; b < 3; b++) {
if (a == b) continue;
int c = 3 - a - b;
f[i][a][b] = min(f[i - 1][a][c] + g[a][b] + f[i - 1][c][b], f[i - 1][a][b] + g[a][c] + f[i - 1][b][a] + g[c][b] + f[i - 1][a][b]);
}
}
}
printf("%lld\n", f[n][0][2]);
return 0;
}
CF392B Tower of Hanoi的更多相关文章
- poj 3601 Tower of Hanoi
Tower of Hanoi Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 1853 Accepted: 635 De ...
- python递归三战:Sierpinski Triangle、Tower of Hanoi、Maze Exploring
本文已做成视频教程投稿b站(视频版相对文本版有一些改进),点击观看视频教程 本文主要通过三个实例来帮助大家理解递归(其展示动画已上传B站): 谢尔宾斯基三角形(Sierpinski Triangle) ...
- 汉诺塔问题(The Tower of Hanoi)的递归算法与非递归算法
非递归算法: 根据圆盘的数量确定柱子的排放顺序: 若n为偶数,按顺时针方向依次摆放 A B C: 若n为奇数,按顺时针方向依次摆放 A C B. 然后进行如下操作: (1)按顺时针方向把圆盘1从现在的 ...
- Tower of Hanoi问题
[问题描述] 有A, B, C三个塔座,A上套有n个直径不同的圆 盘,按直径从小到大叠放,形如宝塔,编号1, 2, 3 … n. 要求将n个圆盘从A移到C,叠放顺序不变,移动过程中遵循 下列原则: w ...
- [POJ1958][Strange Tower of Hanoi]
题目描述 求解 \(n\) 个盘子 \(4\) 座塔的 Hanoi 问题最少需要多少步 问题分析 考虑 \(3\) 座塔的 Hanoi 问题,记 \(f[i]\) 表示最少需要多少步, 则 \(f[i ...
- One usage of recurison: the tower of Hanoi
Statements: This blog was written by me, but most of content is quoted from book[Data Structure wit ...
- 汉诺塔 Tower of Hanoi
假设柱子标为A,B.C.要由A搬至C,在仅仅有一个盘子时,就将它直接搬至C:当有两个盘子,就将B作为辅助柱.假设盘数超过2个.将第二个下面的盘子遮起来,就非常easy了.每次处理两个盘子,也就是:A- ...
- codeforces 392B Tower of Hanoi
把前n个碟子从第一个塔移动到第三个塔有两种方法: 1.把前n-1个移动到第二个塔,把第n个移动到第三个塔,然后把前n-1个从第二个移动到第三个: 2.把前n-1个移动到第三个塔,把第n个移动到第二个塔 ...
- codeforces392B
CF392B Tower of Hanoi 题意翻译 河内塔是一个众所周知的数学难题.它由三根杆和一些可以滑动到任何杆上的不同尺寸的圆盘组成.难题从一个整齐的杆中开始,按照尺寸从小到大的顺序排列,最小 ...
随机推荐
- Socket bind系统调用简要分析
主要查看linux kernel 源码:Socket.c 以及af_inet.c文件 1.1 bind分析 #include <sys/types.h> /* See NOTES */#i ...
- 广度优先遍历&深度优先遍历
一.广度优先算法BFS(Breadth First Search) 基本实现思想 (1)顶点v入队列. (2)当队列非空时则继续执行,否则算法结束. (3)出队列取得队头顶点v: (4)查找顶点v的所 ...
- 【java从入门到精通】day-06-基本运算符-自增自减运算符
1.运算符 java语言支持如下运算符: 算术运算符:+,-,*,/,%,++,-- 赋值运算符:= 关系运算符:>,<,>=,<=,==,!=,instanceof 逻辑运算 ...
- ntpd配置时间同步服务器
修改同步服务器的配置文件/etc/ntp.conf ,删除所有的内容,添加 restrict default nomodify server 127.127.1.0 # local clock fud ...
- [LeetCode题解]876. 链表的中间结点 | 快慢指针
解题思路 使用快慢指针.这里要注意的是,while 的条件会影响当中间节点有两个时,slow 指向的是第一个,还是第二个节点. // 返回的是第一个 while(fast.next != null & ...
- CSS3之flex布局
若要使用flex布局,需在父元素上声明" display : flex ",这样它所有的直系子元素就成为flex元素 1.居中 1)垂直居中:align-items : cente ...
- python-网络安全编程第五天(爬虫模块BeautifulSoup)
前言 昨晚学的有点晚 睡得很晚了,今天早上10点多起来吃完饭看了会电视剧就瞌睡了一直睡到12.50多起来洗漱给我弟去开家长会 开到快4点多才回家.耽搁了不少学习时间,现在就把今天所学的内容总结下吧. ...
- SFTP 服务器cd() 方法和 ls() 方法说明
方法说明: cd():这个方法用于进入某个目录下. 默认情况,当连接SFTP服务器成功后直接进入用户目录,比如我连接自己本机SFTP服务器后进入/Users/mac目录.cd() 方法进入每一个目录都 ...
- python应用(2):写个python程序给自己用
用python写一个程序,然后在命令行上执行,看不到界面(UI),这种程序很常见了,叫命令行程序.然而很多人,特别是不懂程序的人,更需要看到的是一个有界面的,能通过鼠标操作的程序,毕竟已经迈进&quo ...
- 中级实训Android学习记录——Toast、AlertDialog、ProgressBar
学习记录 2020/11/22 Toast Toast Toast是一个消息提示组件 我们可以设置其显示的位置 自定义其显示的内容 对Toast的简单封装可以达到不同的目的 Toast的默认用法 To ...