SHOI2008 汉诺塔

Posted charlesss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

祝各位冬幕节快乐

 

 

 

 

以上是关于SHOI2008 汉诺塔的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1019[SHOI2008]汉诺塔

bzoj1019: [SHOI2008]汉诺塔(dp)

BZOJ 1019 1019: [SHOI2008]汉诺塔 (DP?)

bzoj1019: [SHOI2008]汉诺塔(动态规划)

[SHOI2008]汉诺塔

[SHOI2008]汉诺塔