bzoj 1019 //1019:[SHOI2008]汉诺塔

bzoj 1019 //1019:[SHOI2008]汉诺塔   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1019

 更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

方法一:递推

bzoj 1019

824 kb28 msC++/Edit1378 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 <stdio.h>
#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值