• SHOI2008 汉诺塔


    传送门

     我真爱汉诺塔

    虽说是道紫题,但仔细想想仍适用于基础版本的汉诺塔的递推思路:对于每个情况中的底盘,必须将其上方所有的盘都先挪走。

    转移到这道题上,即将每个底盘上的所有盘全部按当前最高优先级操作挪走。

    进一步简化,把每个底盘上的所有盘当作一个盘,按照最高优先级操作移动即可。

    理论有了,接下来又是我们喜闻乐见的数学推导

    这就是就是就是就是就是道数学题,跟国王游戏一样坑

     


    用 long long定义递推数组sum【110】

    只有一个盘的时候可以一步到位,sum【1】=1

    有两个盘子时,就需要开始考虑优先级的问题:

    因为所有盘从A柱出发,因此要先讨论从A挪到B和C的优先级

    若是B优先于C,则挪动两次后底盘和上面盘将分别处于C、B柱

    若从B出发,C优先于A,则可一步到位,sum【2】=3

    另一种情况下,即A优于C,上面盘会被挪回到A,底盘只能被挪到B,上面盘再挪到B,总共需要sum【2】=5

    回到第五行,若C优先于B,则情况刚好相反,此为两盘的挪动步骤

    那么三盘呢?必须求出数组的前三个数才能递推啊

    我相信聪明机智的各位都能类比上述推法自己推出三盘的步骤,这里就不写了(学校作业要写不完了),因为推导过程是完全一样的。

     

    那么到这里,数据基础问题已经解决了再求个递推式就完美了:(方法极其水但可行)

    Let's 回想一下当初刷openjudge上递推汉诺塔的式子,因为上面盘要挪动两次,底盘挪动一次,我们可得出递推式为 sum[i+1]=sum[i]*2+1

    类比一下,在本题中,上面盘看作一个盘,要挪动的次数假设为x,底盘要挪动的次数假设为y,则递推式为sum[i+1]=sum[i]*x+y

    简单手推两组sum[i+1]和sum[i](i>3)的数据(千万别推错了),代入,用sum[2]和sum[3]表示求出的x和y的值即可(多试几次总会写出对的。。)

    要注意的地方就是求两盘和三盘时,必须保证推出的步骤数正确

    其次最后导出的递推式会很很很长,最好用定义变量拆开表示,不然可能会崩

    (就这两地方导致我暴了4次零)

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 long long miaocannotsay[40];
     5 char x[4];
     6 int miaoa[3][3];
     7 int main()
     8 {
     9     int n;
    10     cin>>n;
    11     for(int i=0;i<6;i++)//读入 
    12     {
    13         scanf("%s",x);;
    14         miaoa[x[0]-'A'][x[1]-'A']=6-i;
    15     }
    16     
    17     miaocannotsay[1]=1;
    18     if(miaoa[0][1]>miaoa[0][2])//AB AC
    19     {
    20         if(miaoa[1][2]<miaoa[1][0])//BC<BA
    21         {
    22             miaocannotsay[2]=5;
    23             miaocannotsay[3]=17;
    24         }
    25         else
    26         {
    27             if(miaoa[2][0]>miaoa[2][1])//CA>CB
    28             {
    29                 miaocannotsay[2]=3;
    30                 miaocannotsay[3]=7;
    31             }
    32             else
    33             {
    34                 miaocannotsay[2]=3;
    35                 miaocannotsay[3]=9;
    36             }
    37         }
    38     }
    39     else 
    40     {
    41     if(miaoa[2][1]<miaoa[2][0])//CB<CA
    42     {
    43      miaocannotsay[2]=5;
    44      miaocannotsay[3]=17;
    45     }
    46     else
    47     {
    48 
    49     if(miaoa[1][0]>miaoa[1][2])//BA>BC
    50     {
    51      miaocannotsay[2]=3;    
    52      miaocannotsay[3]=7;
    53     }
    54     else
    55     {
    56      miaocannotsay[2]=3;
    57      miaocannotsay[3]=9;
    58     }
    59 }
    60 }
    61     int m=(miaocannotsay[2]*miaocannotsay[2]-miaocannotsay[1]*miaocannotsay[3])/(miaocannotsay[2]-miaocannotsay[1]);
    62     int k=miaocannotsay[2]-m;
    63     for(int i=4;i<=n;i++)
    64     miaocannotsay[i]=miaocannotsay[i-1]*k+m;
    65     cout<<miaocannotsay[n];
    66     return 0;
    67 }

    祝各位冬幕节快乐

     

  • 相关阅读:
    NOIP2013 花匠解题报告
    (3) 深入理解SELinux SEAndroid(第三部分
    (2) 深入理解SELinux SEAndroid(第二部分)
    (1) 深入理解SELinux SEAndroid(第一部分)
    SELinux深入理解
    SELinux策略语言--类型强制(编写TE规则)
    Android 6.0中SELinux的TE简介
    8250_fintek
    run "setprop ctrl.start wpa_supplicant" manually
    AOSP Nougat
  • 原文地址:https://www.cnblogs.com/charlesss/p/10155431.html
Copyright © 2020-2023  润新知