$bzoj1019-SHOI2008$ 汉诺塔 $dp$
题面描述
汉诺塔由三根柱子(分别用\(A\ B\ C\)表示)和\(n\)个大小互不相同的空心盘子组成。一开始\(n\)个盘子都摞在柱子\(A\)上,大的在下面,小的在上面,形成了一个塔状的锥形体。
对汉诺塔的一次合法的操作是指:从一根柱子的最上层拿一个盘子放到另一根柱子的最上层,同时要保证被移动的盘子一定放在比它更大的盘子上面(如果移动到空柱子上就不需要满足这个要求)。我们可以用两个字母来描述一次操作:第一个字母代表起始柱子,第二个字母代表目标柱子。例如,\(AB\)就是把柱子\(A\)最上面的那个盘子移到柱子\(B\)。汉诺塔的游戏目标是将所有的盘子从柱子\(A\)移动到柱子\(B\)或柱子\(C\)上面。有一种非常简洁而经典的策略可以帮助我们完成这个游戏。首先,在任何操作执行之前,我们以任意的次序为六种操作\((AB,AC,BA,BC,CA,CB)\)赋予不同的优先级,然后,我们总是选择符合以下两个条件的操作来移动盘子,直到所有的盘子都从柱子\(A\)移动到另一根柱子:
这种操作是所有合法操作中优先级最高的;
这种操作所要移动的盘子不是上一次操作所移动的那个盘子。
可以证明,上述策略一定能完成汉诺塔游戏。现在你的任务就是假设给定了每种操作的优先级,计算按照上述策略操作汉诺塔移动所需要的步骤数。
输入格式
- 输入有两行。第一行为一个整数\(n\ (1\leq n\leq 30)\),代表盘子的个数。第二行是一串大写的\(ABC\)字符,代表六种操作的优先级,靠前的操作具有较高的优先级。每种操作都由一个空格隔开。
输出格式
- 只需输出一个数,这个数表示移动的次数,保证答案\(\leq 10^{18}\)
题解
首先当所有可能的操作都被赋予优先级,并且限制相邻两次操作不能移同一个对象,因此该汉诺塔的移动序列已经被固定。
我们要做的就从最优化变成了合并操作序列中相同的部分,加速计算效率
类比普通的汉诺塔问题,不难发现在移盘子的时候总会不时出现将\(1,.., x\)个盘子以同一个操作序列从某个地方移到某个地方。
令三根柱子分别叫\(x,y,z\)
是这个启发,我们可以设计出如下状态:
- \(f[i][x][y]\)表示\(1,..,i\)个盘子从\(x\)移到\(y\)所需的步数
- 特别的,当\(f[i][x][y]==-1\)时表示\(1,..,i\)个盘子从\(x\)移到\(y\)不合法
这样我们可以写出转移方程
- \[f_{i,x,y}=f_{i-1,x,y}+1+f_{i-1,y,x}+1+f_{i-1,x,y}\\
或\\
f_{i,x,y}=f_{i-1,x,z}+1+f_{i-1,z,y}
\] 注意到当\(1,..,i-1\)个盘子没有移完的时候,我们是不可能去移第\(i\)个盘子的
- 分两种情况
- 一,还有一些盘子在第\(i\)个盘子上,那我们不可能移动第\(i\)个盘子
- 二,第\(i\)个盘子上已经没有盘子了,又分两种情况
- \(1,..,i-1\)个盘子在同一根柱子,那么这时候我们称这\(i-1\)个盘子已经移好了,与假设不符
- \(1,..,i-1\)个盘子不在同一根柱子,那么我们不能移第\(i\)个盘子,因为如果能够移动第\(i\)个盘子,移动到的柱子上已没有比\(i\)小的盘子,但此时两根柱子都有\(1,..,i-1\)中的某一些盘子
- 分两种情况
也就是说,我们必须把\(1,..,i-1\)个盘子移好再移第\(i\)个盘子
故第一个递推方程表示
- 当\(1,..,i-1\)个盘子从\(x\)移到\(y\)合法,且\(1,..,i-1\)个盘子从\(y\)移到\(x\)合法时,
- 我们先将\(1,..,i-1\)个盘子从\(x\)移到\(y\),花费\(f_{i-1,x,y}\)步。
- 因为相邻两次操作对象不能相同,我们只能将第\(i\)个盘子从\(x\)移到\(z\),花费\(1\)步。
- 因为相邻两次操作对象不能相同,我们只能移\(1,..,i-1\)盘子,同时我们不能把这\(1,..,i-1\)盘子移到第\(i\)个盘子所在的\(z\)柱子,因为如此一来,我们在下一步又只能移\(1,..,i-1\)盘子,这是不合法的。因此我们只能把\(1,..,i-1\)盘子移到\(x\)柱子,花费\(f_{i-1,y,x}\)步
- 因为相邻两次操作对象不能相同,我们只能将第\(i\)个盘子从\(x\)移到\(y\),花费\(1\)步。
- 最后我们将\(1,..,i-1\)移回\(y\),花费\(f_{i-1,x,y}\)步
- 当\(1,..,i-1\)个盘子从\(x\)移到\(y\)合法,且\(1,..,i-1\)个盘子从\(y\)移到\(x\)合法时,
第二个递推方程表示
- 当\(1,..,i-1\)盘子从\(x\)移到\(z\)合法,且\(1,..,i-1\)盘子从\(z\)移到\(y\);合法时,
- 我们将\(1,..,i-1\)盘子从\(x\)移到\(z\),花费\(f_{i-1,x,z}\)步
- 因为相邻两次操作对象不能相同,我们只能将第\(i\)个盘子从\(x\)移到\(y\),花费\(1\)步。
- 最后我们将\(1,..,i-1\)盘子从\(z\)移回\(y\),花费\(f_{i-1,z,y}\)步
- 当\(1,..,i-1\)盘子从\(x\)移到\(z\)合法,且\(1,..,i-1\)盘子从\(z\)移到\(y\);合法时,
同时因为操作的优先级,我们不难发现这两个递推是不可能同时成立,但有可能同时不成立。因此当这两个递推式同时不成立时\(f_{i,x,y}=-1\)
关于边界条件,根据题目给出的操作优先级确定
- 例如:从\(x\)向其他柱子移动的操作优先级为\(xy>xz\),因此\(f_{1,x,y}=1,f_{1,x,z}=-1\)
如此递推即可
网上好多博客一本正经地说了一个奇怪的\(dp\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=55;
typedef long long ll;
ll f[MAXN][4][4];
int n;
char s[10][4];
int main(){
scanf("%d",&n);
for (int i=1;i<=6;i++) scanf("%s",s[i]);
for (int i=0;i<3;i++){
f[1][i][0]=f[1][i][1]=f[1][i][2]=-1;
for (int j=1;j<=6;j++){
if (s[j][0]-'A'==i){
int to=s[j][1]-'A';
f[1][i][to]=1;
break;
}
}
}
for (int i=2;i<=n;i++){
for (int j=0;j<3;j++){
for (int k=0;k<3;k++){
int l=3-j-k;
f[i][j][k]=-1;
if (f[i-1][j][k]!=-1&&f[i-1][k][j]!=-1){
f[i][j][k]=f[i-1][j][k]*2+2+f[i-1][k][j];
}
if (f[i-1][j][l]!=-1&&f[i-1][l][k]!=-1){
f[i][j][k]=f[i-1][j][l]+1+f[i-1][l][k];
}
// cout<<i<<" "<<j<<" "<<k<<" "<<f[i][j][k]<<endl;
}
}
}
if (f[n][0][1]!=-1) printf("%lld\n",f[n][0][1]);
else printf("%lld\n",f[n][0][2]);
return 0;
}
随机推荐
- eclipse查看jar包中的class文件出现乱码
参考:http://blog.csdn.net/bell2008/article/details/40978959 1,问题来源是在eclipse中直接查看springside的class(由ecli ...
- mdb
计划开发高性能KV数据库, 学习MongoDB leveldb innodb, 练手贴+日记贴: http://bbs.chinaunix.net/thread-4244870-1-1.html 超高 ...
- 基于 Web 的数据挖掘--自动抽取用 HTML、XML 和 Java 编写的信息
简介: 不可否认,万维网是到目前为止世界上最丰富和最密集的信息来源.但是,它的结构使它很难用系统的方法来利用信息.本文描述的方法和工具将使那些熟悉 Web 最常用技术的开发人员能快速而便捷地获取他们所 ...
- php 与java安卓客户端的查询交互
PHP 服务器端: function getids() { $this->output->set_header('Content-Type: application/json; chars ...
- rabbitmqBat常用指令
激活 RabbitMQ's Management Pluginrabbitmq-plugins.bat enable rabbitmq_management 查看已有用户及用户的角色rabbitmqc ...
- 使用pycharm专业版创建虚拟环境
Location为工程地址 D:\My_python 第二个Location为 虚拟环境放在这个工程下 Base interpreter:基于那个解释器来创建虚拟环境 Create后进入到目录查看下
- 【项目总结】扯一扯电商网站前端css的整体架构设计(1)
最近半忙不忙的写了一个外包网站,网站主要功能是艺术品竞拍和艺术衍生品的销售.工程已经完成了80%左右,现在前后端代码量已经50W行左右,我主要负责的是前端设计和前端布局.下面就先放一个网站的设计图吧, ...
- Hadoop 基础概念
Hadoop就是一个实现了Google云计算系统的开源系统,包括并行计算模型Map/Reduce,分布式文件系统HDFS,以及分布式数据库Hbase,同时Hadoop的相关项目也很丰富,包括ZooKe ...
- SQLServer客户端连接工具(支持2000,20005,2008)
绿色版本, 体积小(不到2M), 支持数据库版本2000 2005 2008 界面仿最经典的SQLServer2000: 下载地址:http://download.csdn.net/detail/gg ...
- Windows上编译zlib
把zlib 1.2.8解压到zlib/zlib-1.2.8 在deflate.c文件中把deflate_copyright改成一个static变量. 在zlib目录底下创建并用Visual Studi ...