bzoj 1019 //1019:[SHOI2008]汉诺塔 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1019
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
方法一:递推
bzoj 1019
824 kb | 28 ms | C++/Edit | 1378 B |
洛谷26ms / 808.00KB / 781B C++
//1019:[SHOI2008]汉诺塔
//在线测评地址https://www.luogu.org/problem/P4285
//弄懂样例是关键,样例2模拟过程如下
//能看出,是有约束条件的汉诺塔
//想了想,要给每根柱子设个栈,存储盘子,从哪根柱子移到那根柱子,对应的最小次数,需开数组存储一下
//感觉还想得不错,不过,目前再也想不下去了。2019-10-12 15:04
//此文https://blog.csdn.net/zhouyuyang233/article/details/57428361思路不错,摘抄如下
/*
考虑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]上面去,再把剩下的一个移动到(0+1+2-x-g[x][i-1])上。
现在原来在x上的i个处在的两个柱子上,其中一个放了1个盘子,另一个放了i-1个盘子。
设g[x][i-1]=y,即i-1个盘子所在的柱子是y;0+1+2-x-g[x][i-1]=z,即一个盘所在的柱子是z。
分两种情况讨论:
(1)若g[y][i-1]=z,那么把这i-1个直接移到z上转移就完成了。
g[x][i]=z f[x][i]=f[x][i-1]+1+f[y][i-1]
(2)若g[y][i-1]=x,这种情况要麻烦一些:
把i-1个从y移动到x上,再把1个从z移动到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]
*/
//样例通过,提交AC.2019-10-13 21:51
#include
#define LL long long
int n,g[5][35];
LL f[5][35];
char cmd[10][5];
int main(){
int i,j,x,y,z;
scanf("%d",&n);
for(i=0;i<6;i++)scanf("%s",cmd[i]);
for(i=0;i<3;i++)//初始化,只有1个盘子的情形
for(j=0;j<6;j++)
if(cmd[j][0]=='A'+i){//'A'+i与起始柱子匹配
g[i][1]=cmd[j][1]-'A';//目标柱子
f[i][1]=1;
break;
}
for(i=2;i<=n;i++)//只有1个盘子,只有2个盘子,......,只有n个盘子
for(j=0;j<3;j++){//起始柱子位置
y=g[j][i-1];//j起始柱子;y转移的i-1个盘子的柱子;z转移的1个盘子的柱子
f[j][i]=f[j][i-1]+1;//i分成i-1,1两堆柱子
z=0+1+2-j-y;
if(g[y][i-1]==z){
f[j][i]+=f[y][i-1];//1个最大的盘子不在j位置上,该盘子,一定是最后移动的。
g[j][i]=z;
}else{//g[y][i-1]既不是y,又不是z,那只能是j
f[j][i]+=f[y][i-1]+1+f[j][i-1];//i-1从y移到j;1从z移到y;i-1从j移到y//1个最大的盘子不在j位置上,该盘子,一定是最后移动的。
g[j][i]=y;
}
}
printf("%lld\n",f[0][n]);
return 0;
}