1. 程式人生 > >bzoj1019 / P4285 [SHOI2008]漢諾塔

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