bzoj1019 / P4285 [SHOI2008]漢諾塔
阿新 • • 發佈:2018-12-26
遞推
題目給出了優先順序,那麼走法是唯一的。
我們用$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)//View Code倒著更新方便存優先順序。 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 }