• BZOJ 1019 汉诺塔


    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[i][j]表示从i号杆子移动j个铁片到最优柱子的最少步数,g[i][j]表示从i号杆子移动j个铁皮的最优柱子的编号。
    然后就是汉诺塔的经典转移了(以下为了方便叙述,i表示杆上的铁片个数,用x表示原杆,y=g[x][i-1],z表示另外一根杆);
    从x移动i个铁片,最优方案是先把x上的i-1个铁片移动到y,再移动最后一个到z,最后再从y上将剩下的i-1个铁片移动回来。
    但是由于本题的最优方案是按照优先级来的,所以我们要分类讨论一下。
    1.若g[y][i-1]=z,我们就可以直接将y上的i-1个铁片移动到z上:f[x][i]=f[x][i-1]+1+f[y][i-1],g[x][i]=z。
    2.若g[y][i-1]=x,我们就得将y上的i-1个铁片移动到x上,但是由于不能移动相同的盘子,所以只能将z上的一个移上y,然后再将x上的i-1个移动到y上来。
    方程:f[x][i]=f[x][i-1]+1+f[y][i-1]+1+f[xi-1],g[x][i]=y。
    初始化:f[i][1]=1,g[i][1]=在i柱子上移动最优的那一个。
     
     1 #include<cstdio>
     2 #include<cstdlib>
     3 using namespace std;
     4 
     5 #define maxn 40
     6 int n,g[4][maxn];
     7 long long f[4][maxn];
     8 
     9 int main()
    10 {
    11     freopen("1019.in","r",stdin);
    12     freopen("1019.out","w",stdout);
    13     scanf("%d
    ",&n);
    14     char opt[7][3]; int i,x,y,z;
    15     for (i = 1;i <= 6;++i) scanf("%s",opt[i]);
    16     for (i = 1;i <= 6;++i)
    17         if (!g[opt[i][0]-'A'+1][1])
    18             g[opt[i][0]-'A'+1][1] = opt[i][1]-'A'+1,f[opt[i][0]-'A'+1][1] = 1;
    19     for (i = 2;i <= n;++i)
    20         for (x = 1;x <= 3;++x)
    21         {
    22             y = g[x][i-1]; z = 6-x-y;
    23             f[x][i] += f[x][i-1] + 1;
    24             if (g[y][i-1] == z)
    25             {
    26                 f[x][i] += f[y][i-1];
    27                 g[x][i] = z;
    28             }
    29             else
    30             {
    31                 f[x][i] += f[y][i-1]+1+f[x][i-1];
    32                 g[x][i] = y;
    33             }
    34         }
    35     printf("%lld",f[1][n]);
    36     fclose(stdin); fclose(stdout);
    37     return 0;
    38 }
    View Code

    参考BY:http://blog.sina.com.cn/s/blog_76f6777d0101b8l1.html 

  • 相关阅读:
    最短路径-Dijkstra算法(转载)
    递归算法到非递归算法的转换
    向量点乘(内积)和叉乘(外积、向量积)概念及几何意义(转载)
    数据预处理之独热编码(One-Hot Encoding)(转载)
    MyEclipse中手工添加dtd支持
    怎样sublime显示文件夹
    sublime_Text3中snippet设置信息头(包括作者、日期)
    解决Sublime_Text不能安装插件的方法
    Python设置默认编码为UTF-8
    解决火狐启动缓慢的方法
  • 原文地址:https://www.cnblogs.com/mmlz/p/4268871.html
Copyright © 2020-2023  润新知