首页 > 其他 > 详细

Luogu P4285 [SHOI2008]汉诺塔

时间:2021-02-18 23:24:49      阅读:34      评论:0      收藏:0      [点我收藏+]

大家知道简单的汉诺塔怎么做吗?

有个公式对吧

就是\(2^n-1\)

操作就是将第一个柱子除底盘外的移到第二个柱子,然后把底盘移到第三个柱子,然后把第二个柱子的盘子移动到第三个

但基本的汉诺塔问题的操作是没有限制的,就是你想移哪儿移哪儿,但是这题不一样,这题强制了一个操作优先级,所以要用不同的方法去做。

f[x][i]: 第x号柱子移i个盘子到最优柱子的最优解
p[x][i]:第x号柱子移i个盘子到p[x][i]号柱子是最优解

那么就有两种情况,第一种就是普通的汉诺塔移动
也就是上面所讲的:

\(f[a][i]=f[a][i-1]+1+f[b][i-1];\)

另外一种就是特殊的
a上i-1个盘子移至b上,将a上的第i个盘子,移至c。由于i个盘子还没叠到一起,所以接下来还要再次移动b上的i-1个

如果移到c的话就是经典算法

如果\(i-1\)个盘子移到\(a\)的话,那么最终就是移到\(b\)柱子上

\(f[a][i]=f[a][i-1]+1+f[b][i-1]+1+f[a][i-1];\)

上代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int p[4][31],x[10],y[10];
int n;
LL f[4][31];
int main()
{
    scanf("%d",&n);
    char s[3];
    for(int i=1;i<=6;i++)
    {
        scanf("%s",s);
        x[i]=s[0]-‘A‘+1,y[i]=s[1]-‘A‘+1;
    }
    for(int i=6;i>=1;i--) p[x[i]][1]=y[i];//倒着来的原因是优先级高的会覆盖优先级低的,被覆盖的我们就不要了
    for(int i=1;i<=3;i++) f[i][1]=1LL;
    for(int i=2;i<=n;i++)
    {
        for(int a=1;a<=3;a++)
        {
            int b=p[a][i-1],c=6-a-b;//c是什么?你看一号二号三号加起来是6嘛,减去其他两个不就是剩下那个了?
            if(p[b][i-1]==c)
            {
                f[a][i]=f[a][i-1]+1+f[b][i-1];//1是底盘移动的步数
                p[a][i]=c;
            }
            else if(p[b][i-1]==a)
            {
                f[a][i]=f[a][i-1]+1+f[b][i-1]+1+f[a][i-1];
                p[a][i]=b;
            }
        }
    }
    printf("%lld\n",f[1][n]);
    return 0;
}

Luogu P4285 [SHOI2008]汉诺塔

原文:https://www.cnblogs.com/will1477/p/14411409.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!