zoukankan      html  css  js  c++  java
  • bzoj1019: [SHOI2008]汉诺塔(dp)

    1019: [SHOI2008]汉诺塔

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 1739  Solved: 1062
    [Submit][Status][Discuss]

    Description

      汉诺塔由三根柱子(分别用A B C表示)和n个大小互不相同的空心盘子组成。一开始n个盘子都摞在柱子A上,
    大的在下面,小的在上面,形成了一个塔状的锥形体。

     

      对汉诺塔的一次合法的操作是指:从一根柱子的最上层拿一个盘子放到另一根柱子的最上层,同时要保证被移
    动的盘子一定放在比它更大的盘子上面(如果移动到空柱子上就不需要满足这个要求)。我们可以用两个字母来描
    述一次操作:第一个字母代表起始柱子,第二个字母代表目标柱子。例如,AB就是把柱子A最上面的那个盘子移到
    柱子B。汉诺塔的游戏目标是将所有的盘子从柱子A移动到柱子B或柱子C上面。有一种非常简洁而经典的策略可以帮
    助我们完成这个游戏。首先,在任何操作执行之前,我们以任意的次序为六种操作(AB、AC、BA、BC、CA和CB)
    赋予不同的优先级,然后,我们总是选择符合以下两个条件的操作来移动盘子,直到所有的盘子都从柱子A移动到
    另一根柱子:(1)这种操作是所有合法操作中优先级最高的;(2)这种操作所要移动的盘子不是上一次操作所移
    动的那个盘子。可以证明,上述策略一定能完成汉诺塔游戏。现在你的任务就是假设给定了每种操作的优先级,计
    算按照上述策略操作汉诺塔移动所需要的步骤数。

    Input

      输入有两行。第一行为一个整数n(1≤n≤30),代表盘子的个数。第二行是一串大写的ABC字符,代表六种操
    作的优先级,靠前的操作具有较高的优先级。每种操作都由一个空格隔开。

    Output

      只需输出一个数,这个数表示移动的次数。我们保证答案不会超过10的18次方。

    Sample Input

    3
    AB BC CA BA CB AC

    Sample Output

    7
     
    /*
    如果是普通汉诺塔
    操作就是将第一个柱子除底盘外的移到第二个柱子,然后把底盘移到第三个柱子,然后把第二个柱子的盘子移动到第三个
    但基本的汉诺塔问题的操作是没有限制的,就是你想移哪儿移哪儿,但是这题不一样,这题强制了一个操作优先级,所以要用不同的方法去做。
    f[x][i]: 第x号柱子移i个盘子到最优柱子的最优解 
    p[x][i]:第x号柱子移i个盘子到p[x][i]号柱子是最优解
    那么就有两种情况,第一种就是普通的汉诺塔移动 
    f[a][i]=f[a][i-1]+1+f[b][i-1];
    另外一种就是特殊的 
    a上i-1个盘子移至b上,将a上的第i个盘子,移至c。由于i个盘子还没叠到一起,所以接下来还要再次移动b上的i-1个
    如果移到c的话就是经典算法
    如果i-1个盘子移到a的话,那么最终就是移到b柱子上
    f[a][i]=f[a][i-1]+1+f[b][i-1]+1+f[a][i-1]; 
    */
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    
    #define ll long long 
    
    using namespace std;
    int p[4][31],x[10],y[10];
    int n; char s[3];
    ll f[4][31];
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=6;i++)
        {
            scanf("%s",s);
            x[i]=s[0]-'A'+1,y[i]=s[1]-'A'+1;
        }
        for(int i=6;i>=1;i--) p[x[i]][1]=y[i];//倒着来的原因是优先级高的会覆盖优先级低的,被覆盖的我们就不要了
        for(int i=1;i<=3;i++) f[i][1]=1LL;
        for(int i=2;i<=n;i++)
        {
            for(int a=1;a<=3;a++)
            {
                int b=p[a][i-1],c=6-a-b;//c是什么?一号二号三号加起来是6嘛,减去其他两个不就是剩下那个了?
                if(p[b][i-1]==c)
                {
                    f[a][i]=f[a][i-1]+1+f[b][i-1];//1是底盘移动的步数
                    p[a][i]=c;
                }
                else if(p[b][i-1]==a)
                {
                    f[a][i]=f[a][i-1]+1+f[b][i-1]+1+f[a][i-1];
                    p[a][i]=b;
                }
            }
        }
        printf("%lld
    ",f[1][n]);
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    Druid 使用 Kafka 将数据载入到 Kafka
    Druid 使用 Kafka 数据加载教程——下载和启动 Kafka
    Druid 集群方式部署 —— 启动服务
    Druid 集群方式部署 —— 端口调整
    Druid 集群方式部署 —— 配置调整
    Druid 集群方式部署 —— 配置 Zookeeper 连接
    Druid 集群方式部署 —— 元数据和深度存储
    Druid 集群方式部署 —— 从独立服务器部署上合并到集群的硬件配置
    Druid 集群方式部署 —— 选择硬件
    Druid 独立服务器方式部署文档
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7425349.html
Copyright © 2011-2022 走看看