bzoj1019 / 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 }