[bzoj1019][SHOI2008]汉诺塔【dp】
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1019
【题解】
考虑 n=i 与 i+1 时答案的联系:
设 f[i][j] 为第 j 个柱子上有 i 个盘子,把它们搬到另一个柱子上(可以是A)的答案。
g[i][j] 为搬空后会留在哪个柱子上。(一定唯一)
那么 i+1 的方案前 f[i][A] 步一定与 i 相同。设 g[i][A]=X
接下来一步是把第 i+1 块移到空的柱子上。设空的柱子为 Y
接下来有两种情况:
1. g[i][X]=Y 那么直接移过去即可 ans=f[i][A]+1+f[i][X] 。
2. g[i][X]=A 那么需要移两次,一次把 X 的 i 个柱子移到 A ,在移动一次最大的盘子再把 A 上的柱子移到 X 上。ans=f[i][A]+1+f[i][X]+1+f[i][A]
/* --------------
user Vanisher
problem bzoj-1019
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define N 41
using namespace std;
const int k=6;
int ans,n,mp[7][2],g[3][N],to[3];
ll f[3][N];
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
char getC(){
char ch=getchar();
while (ch<'A'||ch>'Z') ch=getchar();
return ch;
}
int main(){
n=read();
for (int i=1; i<=k; i++)
mp[i][0]=getC()-'A', mp[i][1]=getC()-'A';
for (int i=0; i<3; i++){
for (int j=1; j<=k; j++)
if (mp[j][0]==i){
to[i]=mp[j][1];
break;
}
}
f[0][1]=1; g[0][1]=to[0];
f[1][1]=1; g[1][1]=to[1];
f[2][1]=1; g[2][1]=to[2];
for (int i=2; i<=n; i++)
for (int j=0; j<3; j++){
if (g[g[j][i-1]][i-1]==j)
f[j][i]=f[j][i-1]+1+f[g[j][i-1]][i-1]+1+f[j][i-1],g[j][i]=g[j][i-1];
else f[j][i]=f[j][i-1]+1+f[g[j][i-1]][i-1], g[j][i]=g[g[j][i-1]][i-1];
}
printf("%lld\n",f[0][n]);
return 0;
}