题目链接

题目大意:把汉诺双塔按指定顺序排好的最少步数

我写这题写了很久...终于发现不dp不行

把一个双重塔从一根桩柱移动到另一根桩柱需要移动多少次?

最佳策略是移动一个双重 (n-1) 塔,接着移动两个最大的圆盘,然后再次移动双重 (n-1) 塔,从而 $A_n = 2 * A_{n-1} + 2,A_n = 2^{n+1} - 2 $。

这会交换两个最大的圆盘,其余的 \(2n-2\) 个圆盘次序不变。

如果在最后的排列中要把所有同样尺寸的圆盘恢复成原来的从上到下的次序,需要移动多少次?

有两个想法:(假设初始盘子都在A柱上)

一:先把双重(n-1)塔按顺序在C柱上搞好,再2步把最大的两个盘丢到B柱上,\(A_{n-1}\)步把双重(n-1)塔丢A柱子上,再2步把最大的两个盘丢到C柱上,最后\(A_{n-1}\)步把双重(n-1)塔丢C柱子上

发现这样顺序刚好是对的\(B_n=B_{n-1}+2^{n+1}\)

二:先把双重(n-1)塔按顺序在C柱上搞好,再移动靠上的一个大圆盘J到B柱,把(n-1)塔再移上B柱上的大圆盘,移动另一个大圆盘H,把(n-1)塔移到一根空柱上,把H放在J上,再把(n-1)塔移到两个大圆盘上,发现顺序刚好也是对的

\(B_n = A_{n-1} + 1 + A_{n-1} + 1 + A_{n-1} + 1 + A_{n-1} = 4A_{n-1} + 3 = 4(2^{n} - 2) + 3 = 2^{n+2} - 5\)

然后你发现这两个式子是等价的。。。

我的想法:除了最底下的两个盘子,如果两个盘子的顺序是倒过来的,那么在移动的时候就先正着与比它小的盘子放好一堆,在移动更大的两个盘子的时候用\(A_n\)的做法,顺序不就又倒过来了吗?

事实证明这是错的,无法保证最优性

所以dp吧

g[i]表示把前\(2(i-1)\)块按顺序排好,最后两块也按要求顺序排好的最小步数

f[i]表示把前\(2(i-1)\)块按顺序排好,最后两块与要求顺序相反最小步数

\(f[i]=g[i-1]+4+2^{i+1}-4=g[i-1]+2^{i+1}\)

表示先把i-1层按顺序移出去,再移动第i层,i-1层移到另一个柱上,再移动第i层,i-1层移到第i层上,这样顺序刚好是对的(类似\(B_i\)的移法)

\(g[i]=f[i-1]+2+ 2^i-2=f[i-1]+ 2^i\)

表示先把i-1层移出去,再把i层的两个盘移出,再把i-1层移上去

结合代码理解

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;++i)
using namespace std;
typedef long long ll;
typedef double db;
char cch;
inline int rd(){
int x=0,fl=1;
cch=getchar();
while(cch>'9'||cch<'0'){
if(cch=='-') fl=-1;
cch=getchar();
}
while(cch>='0'&&cch<='9') x=(x<<3)+(x<<1)+cch-'0',cch=getchar();
return x*fl;
}
inline void add(int a[],int b[]){
int x=0,len=max(a[0],b[0]);
rep(i,1,len){
a[i]+=b[i]+x,x=a[i]/10000,a[i]%=10000;
}
if(x) a[++len]=x;
a[0]=len;
}
int p[2009][2009],f[2009],g[2009],a[4009];//注意是4009!
int main(){
int n=rd();
p[0][0]=1,p[0][1]=1;
rep(i,1,n+1) add(p[i],p[i-1]),add(p[i],p[i-1]);
rep(i,1,n) a[2*(n-i+1)]=rd(),a[2*(n-i+1)-1]=rd();
if(a[1]<a[2]) g[0]=1,g[1]=3,f[0]=1,f[1]=2;
else g[0]=1,g[1]=2,f[0]=1,f[1]=3;
int *ff=f,*gg=g;//这样可以只swap指针,swap数组是o(n)的
rep(i,2,n){
if(a[i*2]<a[i*2-1]) swap(ff,gg),add(ff,p[i+1]),add(gg,p[i]);//g是2 1顺序,f是1 2顺序,f[i]=g[i-1]+2^{i+1},g[i]=f[i-1]+2^i,所以swap
else add(ff,p[i]),add(gg,p[i+1]);//g是1 2,f是2 1, 此时g相当于上面的f,f相当于上面的g,所以转移方程互换
}
printf("%d",gg[gg[0]]);
for(int i=gg[0]-1;i;--i) printf("%04d",gg[i]);
}
/*
4
8 7 5 6 3 4 1 2
*/

Gym-100451B:Double Towers of Hanoi的更多相关文章

  1. POJ1958:Strange Towers of Hanoi

    我对状态空间的理解:https://www.cnblogs.com/AKMer/p/9622590.html 题目传送门:http://poj.org/problem?id=1958 题目要我们求四柱 ...

  2. The Towers of Hanoi Revisited---(多柱汉诺塔)

    Description You all must know the puzzle named "The Towers of Hanoi". The puzzle has three ...

  3. [CareerCup] 3.4 Towers of Hanoi 汉诺塔

    3.4 In the classic problem of the Towers of Hanoi, you have 3 towers and N disks of different sizes ...

  4. POJ 1958 Strange Towers of Hanoi

    Strange Towers of Hanoi Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 3784 Accepted: 23 ...

  5. ural 2029 Towers of Hanoi Strike Back (数学找规律)

    ural 2029 Towers of Hanoi Strike Back 链接:http://acm.timus.ru/problem.aspx?space=1&num=2029 题意:汉诺 ...

  6. POJ1958 Strange Towers of Hanoi [递推]

    题目传送门 Strange Towers of Hanoi Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3117   Ac ...

  7. poj 1920 Towers of Hanoi

    Towers of Hanoi Time Limit: 3000MS   Memory Limit: 16000K Total Submissions: 2213   Accepted: 986 Ca ...

  8. zoj 2338 The Towers of Hanoi Revisited

    The Towers of Hanoi Revisited Time Limit: 5 Seconds Memory Limit: 32768 KB Special Judge You all mus ...

  9. POJ 1958 Strange Towers of Hanoi 解题报告

    Strange Towers of Hanoi 大体意思是要求\(n\)盘4的的hanoi tower问题. 总所周知,\(n\)盘3塔有递推公式\(d[i]=dp[i-1]*2+1\) 令\(f[i ...

随机推荐

  1. opencv2\core\cuda.hpp(106): error C2059: 语法错误:“常量”

    在 cuda.hpp 中, virtual void free(GpuMat* mat) = 0;   -> virtual void _free(GpuMat* mat) = 0;

  2. Git-用 cherry-pick 挑好看的小樱桃

         版权声明:本文为博主原创文章,转载请在文章明显位置标明文章原属哦. https://blog.csdn.net/qq_32452623/article/details/79449534 ti ...

  3. Java中的break,continue关于标签的用法(转载)

    Java的控制循环结构中是没有关键字goto的,这种做法有它的好处,它提高了程序流程控制的可读性,但是也有不好的地方,它降低了程序流程控制的灵活性,所以说,“上帝是公平的”.所以,Java为了弥补这方 ...

  4. java.lang包【Object类】

    基本描述: (1)Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入: (2)Object类是所有Java类的祖先.每个类都使用 Obje ...

  5. cpp11_thread线程

    一.进程与线程 cpu一般有m核n线程的说法,那么该cpu只能同时运行n个线程(线程中没有sleep). #include <thread> #include <mutex> ...

  6. Day 4-11 re正则表达式

    正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' ...

  7. 莫烦keras学习自修第三天【回归问题】

    1. 代码实战 #!/usr/bin/env python #!_*_ coding:UTF-8 _*_ import numpy as np # 这句话不知道是什么意思 np.random.seed ...

  8. php配置-解决大数据超多字段的POST方式提交无法完全接受的问题

    例如:在盘点表的数据提交中出现了POST大量数据超多字段的将近2000个字段,部分字段没有接受:修改方法为修改php.ini 将max_input_var调大,该值默认为1000 max_input_ ...

  9. Java面向对象之多态的静态和动态实现

    简单而言: 静态多态:即为重载,方法的重载 动态多态:即为重写/覆盖,方法的重写

  10. react使用setstate注意的两点

    1.this.state里的属性不修改,或是只修改一个,那么不修改的剩下的属性不会被变动. this.state={ name:"Aliece", age:19, msg:&quo ...