bzoj1019: [SHOI2008]汉诺塔

来源:互联网 发布:linux下安装数据库 编辑:程序博客网 时间:2024/05/16 06:49

传送门

考虑dp方程:

f[x][i]表示第x个柱子上有i个盘子,把他们都移动到g[x][i]这个柱子上要花得步数。

首先考虑i=1,因为操作有优先顺序,因此g[x][1]可以确定,f[x][1]都是1。

接下来考虑任意的i,那么我们需要把i-1个移动到g[x][i-1]上面去,再把剩下的一个移动到(1+2+3-x-g[x][i-1])上。

现在原来在x上的i个处在的两个柱子上,其中一个放了1个盘子,另一个放了i-1个盘子。

设g[x][i-1]=y,即i-1个盘子所在的柱子是y;1+2+3-x-g[x][i-1]=k,即一个盘所在的柱子是k。

分两种情况讨论:

(1)若g[y][i-1]=k,那么把这i-1个直接移到k上转移就完成了。

g[x][i]=k   f[x][i]=f[x][i-1]+1+f[y][i-1]

(2)若g[y][i-1]=x,这种情况要麻烦一些:

把i-1个从y移动到x上,再把1个从k移动到y上,最后把i-1个从x上移动到y上。

g[x][i]=y  f[x][i]=f[x][i-1]+1+f[y][i-1]+1+f[x][i-1]

#include<iostream>#include<cstdio>long long f[3][35];int g[3][35],n,y,z;char a[6][3];int main(){scanf("%d",&n);for (int i=0;i<6;i++) scanf("%s",&a[i]);for (int i=0;i<3;i++)for (int j=0;j<6;j++)if (a[j][0]=='A'+i){f[i][1]=1;g[i][1]=a[j][1]-'A';break;}for (int i=2;i<=n;i++)for (int j=0;j<3;j++){y=g[j][i-1];z=3-y-j;f[j][i]=f[j][i-1]+1;if (g[y][i-1]==z){f[j][i]+=f[y][i-1];g[j][i]=z;}else{f[j][i]+=f[y][i-1]+1+f[j][i-1];g[j][i]=y;}}printf("%lld",f[0][n]);return 0;}


1 0