• 题面描述

    • 汉诺塔由三根柱子(分别用\(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\)移到\(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}\)步
    • 同时因为操作的优先级,我们不难发现这两个递推是不可能同时成立,但有可能同时不成立。因此当这两个递推式同时不成立时\(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;
}

随机推荐

  1. es学习-java操作 2.4.0版本

    package esjava; import org.elasticsearch.action.bulk.*;import org.elasticsearch.action.delete.Delete ...

  2. SimpleDateFormat是线程不安全的

    线程不安全的SimpleDateFormat SimpleDateFormat是线程不安全的 SimpleDateFormat是Java提供的一个格式化和解析日期的工具类,日常开发中应该经常会用到,但 ...

  3. CodeForces 339B Xenia and Ringroad(水题模拟)

    题意:给定 n 个地方,然后再给 m 个任务,每个任务必须在规定的地方完成,并且必须按顺序完成,问你最少时间. 析:没什么可说的,就是模拟,记录当前的位置,然后去找和下一个位置相差多长时间,然后更新当 ...

  4. Ubuntu 将应用程序 固定到快快速启动栏(以Sublime为例)

    因为Sublime Text并不是需要安装,所以缺少Ubuntu桌面运行的一些基本配置,比如不能将它加入桌面侧边的启动器. 而Ubuntu上也没有快捷方式的说法,而通过软件中心安装的软件就有图标,并能 ...

  5. 团体程序设计天梯赛L3-010 是否完全二叉搜索树 2017-03-24 16:12 29人阅读 评论(0) 收藏

    L3-010. 是否完全二叉搜索树 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 将一系列给定数字顺序插入一个初始为空的二叉搜 ...

  6. CodeSmith Generator 6.5 自动生成后的源码分析

    1,NetTiers代码结构流程分析: 2,CodeSmithNetTiers使用实践总结 参看流程结构图和实体定义文件关系图,可以看出自动代码生成后,若是手工来调,还是很麻烦的.鉴于此,建议:1,若 ...

  7. memcached整理の基本使用

    memcached 客户端与服务器端的通信比较简单,使用的基于文本的协议,而不是二进制协议.(http 协议也是这样), 因此我们通过telnet 即可与memcached 作交互. # 格式teln ...

  8. Linq集合操作之Intersect,Except,Union源码分析

    Linq集合操作之Intersect,Except,Union源码分析 linq的集合运算 常见的集合运算有哪些? 这三个扩展方法在我们实际使用中用的还是非常多的,而且这里还涉及到了“复杂度” 无算法 ...

  9. Reporting Service服务SharePoint集成模式安装配置(5、安装 SQL SERVER 2012 SP1产品)

    有过SQL2012 数据库安装经验的,可以跳过这一步骤直接进入第五步骤:RS外接程序的安装  数据库安装工具:SQLServer2012 SP1 Name:SQLServer2012SP1-FullS ...

  10. redis----内部数据结构学习

    整数集合 1.应用 用于有序.无重复的保存多个整数值 自动选择该用什么长度的整数类型保存数据