[bzoj1019][SHOI2008]汉诺塔【dp】

本文介绍了一种解决汉诺塔问题的有效算法。通过动态规划的方法,定义了状态转移方程,实现了一个从初始状态到目标状态的最优移动序列。讨论了不同状态下盘子移动的策略,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1019
【题解】
考虑 n=ii+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 那么需要移两次,一次把 Xi 个柱子移到 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值