【题解】2019,4.24模拟赛(汉诺塔)

\(Description:\)

给出汉诺塔玩了几步之后的状态,\(pos[i]\) 表示第 \(i\) 小的盘子在 \(pos[i]\)。 求出玩到现在是不是最优解,如果是最优解,那么现在是第几步。

\(Sample\) \(Input:\)

2

3 1

\(Sample\) \(Output:\)

1

\(Solution:\)

害怕,我居然从来没做过汉诺塔的题。。。

不会做汉诺塔的我瑟瑟发抖。

其实这题会做汉诺塔的人大概都会,就是考虑:

首先先把当前状态还原回初始柱。

然后在按最优解把盘子移到第二根。

两者步数之和一加,看看和最优解是否次数相同。

汉诺塔 \(n\)个盘子的最优解移动次数是 \(2^{n}-1\)

那么先来看一下普通的汉诺塔代码。

inline int Get_next(int now,int to){
    if(now==1) return (!(to==2));
    if(2==to) return Get_next(now-1,to);
    int useful=1;// 找到下一根可用的中转柱子
    while(useful==pos[now] || useful==to) useful++;
    return ((1<<(now-1))+Get_next(now-1,useful));   
    // 把上面一堆放到中转柱上,最优方法为1<<(now-1)-1,
    // 因为还要加上当前这个圈移到目标柱上
}

倒做回去的代码其实也差不多:

inline int Get_pre(int now,int from,int to){
    // from =>现在在的柱子
    // to   =>要去的柱子
    if(now==1) return (!(from==to));
    if(from==to) return Get_pre(now-1,to,pos[now-1]);
    int useful=1;
    while(useful==from || useful==to) useful++;
    return ((1<<(now-1))+Get_pre(now-1,useful,pos[now-1]));
}

完整代码:

#include<cstdio>
#include<iostream>
#define int long long

using std::scanf;
using std::printf;

const int N=32;

int n,part1_ans,part2_ans;
int pos[N];

inline int Get_pre(int now,int from,int to){
    if(now==1) return (!(from==to));
    if(from==to) return Get_pre(now-1,to,pos[now-1]);
    int useful=1;
    while(useful==from || useful==to) useful++;
    return ((1<<(now-1))+Get_pre(now-1,useful,pos[now-1]));
}
inline int Get_next(int now,int to){
    if(now==1) return (!(to==pos[now]));
    if(pos[now]==to) return Get_next(now-1,to);
    int useful=1;
    while(useful==pos[now] || useful==to) useful++;
    return ((1<<(now-1))+Get_next(now-1,useful));   
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i) scanf("%lld",&pos[i]);
    part1_ans=Get_pre(n,1,pos[n]);
    part2_ans=Get_next(n,2);
    if(part1_ans+part2_ans>(1<<n)-1) return puts("-1"),0;
    printf("%lld\n",part1_ans);
    return 0;
}

转载于:https://www.cnblogs.com/JCNL666/p/10765438.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值