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]$可以预处理。

 #include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int g[][],n;
long long f[][];
char s[][];
int main(){
scanf("%d",&n);
for(int i=;i;--i) scanf("%s",s[i]);
for(int i=;i<=;++i)//倒着更新方便存优先级。
g[][s[i][]-'A']=s[i][]-'A';
f[][]=f[][]=f[][]=;
for(int i=;i<=n;++i)
for(int x=;x<=;++x){
int y=g[i-][x],z=-x-y;
if(g[i-][y]==z)
g[i][x]=z,f[i][x]=f[i-][x]++f[i-][y];
else if(g[i-][y]==x)
g[i][x]=y,f[i][x]=f[i-][x]++f[i-][y]++f[i-][x];
}
printf("%lld",f[n][]);
return ;
}
上一篇:java开发之提高java和mysql代码性能和质量


下一篇:java编程思想-复用类总结