【题解】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;
}
上一篇:Some useful Javascript variables/functions in Sharepoint


下一篇:「工具」Some useful tools