bzoj1019 / P4285 [SHOI2008]汉诺塔

P4285 [SHOI2008]汉诺塔

递推

题目给出了优先级,那么走法是唯一的。

我们用$0,1,2$代表$A,B,C$三个柱子

设$g[i][x]$为第$x$根柱子上的$i$个盘子,经过演变后最终一定会全部转移到第$g[i][x]$根柱子上

$f[i][x]$表示第$x$根柱子上的$i$个盘子,转移到第$g[i][x]$根柱子上所用的步数。

现在开始递推。

假设有$i$个盘子在第$x$个盘子上

设$y=g[i-1][x],z=3-x-y$,表示$i-1$个盘子从$x$转移到$y$后,第$i$个盘子转移到$z$柱上

分类讨论:

1.当$g[i-1][y]=z$时,显然最终$i$个盘子都到$z$上

$i-1$个盘子到$y$柱上 $-->$ 第$i$个盘子到$z$柱上 $-->$ $i-1$个盘到$z$上

$g[i][x]=z,f[i][x]=f[i-1][x]+1+f[i-1][y]$

2.当$g[i-1][y]=x$时

$i-1$个盘子到$y$柱上 $-->$ 第$i$个盘子到$z$柱上 $-->$ $i-1$个盘到$x$上 $-->$ 第$i$个盘子到$y$柱上 $-->$ $i-1$个盘到$y$上$

$g[i][x]=y,f[i][x]=f[i-1][x]+1+f[i-1][y]+1+f[i-1][x]$

而$f[1][0/1/2],g[1][0/1/2]$可以预处理。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int g[33][3],n;
 6 long long f[33][3];
 7 char s[7][3];
 8 int main(){
 9     scanf("%d",&n);
10     for(int i=6;i;--i) scanf("%s",s[i]);
11     for(int i=1;i<=6;++i)//倒着更新方便存优先级。
12         g[1][s[i][0]-'A']=s[i][1]-'A';
13     f[1][0]=f[1][1]=f[1][2]=1;
14     for(int i=2;i<=n;++i)
15         for(int x=0;x<=2;++x){
16             int y=g[i-1][x],z=3-x-y;
17             if(g[i-1][y]==z)
18                 g[i][x]=z,f[i][x]=f[i-1][x]+1+f[i-1][y];
19             else if(g[i-1][y]==x)
20                 g[i][x]=y,f[i][x]=f[i-1][x]+1+f[i-1][y]+1+f[i-1][x];
21         }
22     printf("%lld",f[n][0]);
23     return 0;
24 }
View Code

 

posted @ 2018-12-26 20:08  kafuuchino  阅读(40)  评论(0编辑  收藏