1 条题解

  • 0
    @ 2025-8-24 21:32:13

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar cqbzlym
    自见者不明,自是者不彰

    搬运于2025-08-24 21:32:13,当前版本为作者最后更新于2021-02-15 12:25:00,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    本题可以采用双向BFS,别名大模拟。

    原因是本题的反向搜索方式与正向相同,也就是说存在反向搜索的方式。

    cqbzljsqwq 大巨佬的双向BFS强悍的八维数组状态本蒟蒻学不来QwQ

    蒟蒻的当前状态就是一个六位数,直接扔到下标里面标记。

    那么很明显,用六位数比用字符串做状态快了无数倍,同时也会麻烦无数倍。

    比如,本人程序一直很慢的原因是:有超过两小时的时间一直认为存六位数的下标应该开1e7的数组,(107999999=900000110^7-999999=9000001)导致memset直接爆炸。

    设计状态:

    struct node{
        int now;//当前的六位数密码
        int stp;//当前所用步数
        int pos;//当前光标所在位置
        bool flag;//搜索方向,0表示正向,1表示反向
    }
    

    left/right操作好说,直接改变pos的值就行了。

    up/downswap0/swap1是要改变now的某几位上的值,很麻烦。

    我们先存储一个数从左向右每一位对应的单位:

    const int ws[]={1000000,100000,10000,1000,100,10,1};
    //防RE,第0位也要存
    

    假设我们要将numpos上的值更改为x,怎么操作呢?

    我们将num拆成1~(pos-1)pos(pos+1)~6三部分。

    第一部分和第三部分不变,将第二部分修改为x*ws[pos]就行了。

    1~(pos-1)的获取方式:利用C++整除的特性,num/ws[pos-1]*ws[pos-1]就可以得到了。

    (pos+1)~6的获取方式:num%ws[pos]就可以得到pos之后位数的值。

    由此得出上下操作的代码:

    //up or down,获取num的pos位增加chg的结果
    inline int UpOrDown(int num,int pos,int chg){
        int t=num/ws[pos]%10+chg;
        //获取num的pos位变化后的结果,判断是否可以这样变化
        if(t>=0&&t<=9)
            return num/ws[pos-1]*ws[pos-1]+t*ws[pos]+num%ws[pos];
        return num;
    }
    

    以及swap操作:

    //swap0 or swap1,获取num的pos位与chg位交换的结果
    inline int Swap(int num,int pos,int chg){
        int bg=num/ws[pos]%10;//记录pos位本来的数值
        int ed=num/ws[chg]%10;//记录chg位本来的数值
        if(bg==ed)return num;
        num=num/ws[pos-1]*ws[pos-1]+ed*ws[pos]+num%ws[pos];//pos变为ed
        num=num/ws[chg-1]*ws[chg-1]+bg*ws[chg]+num%ws[chg];//chg变为bg
        return num;
    }
    

    然后是调到吐的双向BFS。

    为了方便同时标记走没走过与所用步数,我们事先将vis数组置为-1

    完整代码:

    /*
    (twbfs==大模拟)==true
    */
    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    short vis[1000000][7][2];
    struct node{
        int now;
        int stp,pos;
        //pos: 当前光标位置
        bool flag;
    }S,B,f,tmp;
    queue<node>q;
    const int ws[]={1000000,100000,10000,1000,100,10,1};
    inline int UpOrDown(int num,int pos,int chg){
        int t=num/ws[pos]%10+chg;
        if(t>=0&&t<=9)
            return num/ws[pos-1]*ws[pos-1]+t*ws[pos]+num%ws[pos];
        return num;
    }
    inline int Swap(int num,int pos,int chg){
        int bg=num/ws[pos]%10;
        int ed=num/ws[chg]%10;
        if(bg==ed)return num;
        num=num/ws[pos-1]*ws[pos-1]+ed*ws[pos]+num%ws[pos];
        num=num/ws[chg-1]*ws[chg-1]+bg*ws[chg]+num%ws[chg];
        return num;
    }
    int TWBFS(void){
        //TIANWEN BFS(bushi)
        while(!q.empty()){
            tmp=f=q.front();
            tmp.stp++;
            q.pop();
            if(~vis[f.now][f.pos][!f.flag])
                return f.stp+vis[f.now][f.pos][!f.flag];
            //将光标左移一位
            if(f.pos>1){
                tmp.pos=f.pos-1;
                if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                    vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                    q.push(tmp);
                }
            }
            //将光标右移一位
            if(f.pos<6){
                tmp.pos=f.pos+1;
                if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                    vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                    q.push(tmp);
                }
            }
            //记得把光标移回来,不要像本蒟蒻一样傻傻踩坑
            tmp.pos=f.pos;
            //将光标所在位置的数值增加1
        	tmp.now=UpOrDown(f.now,f.pos,1);
            if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                q.push(tmp);
            }
            //将光标所在位置的数值减少1
        	tmp.now=UpOrDown(f.now,f.pos,-1);
            if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                q.push(tmp);
            }
            //swap0
            if(f.pos!=1){
                tmp.now=Swap(f.now,f.pos,1);
                if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                    vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                    q.push(tmp);
                }
            }
            //swap1
        	if(f.now!=6){
                tmp.now=Swap(f.now,f.pos,6);
                if(vis[tmp.now][tmp.pos][tmp.flag]==-1){
                    vis[tmp.now][tmp.pos][tmp.flag]=tmp.stp;
                    q.push(tmp);
                }
            }
        }
        return 114514;
    }
    int main(){
        scanf("%d%d",&S.now,&B.now);
        memset(vis,-1,sizeof(vis));
        S.pos=1;
        q.push(S);
        B.flag=1;
        vis[S.now][1][0]=0;
        //最终密码的光标在每一位都有可能出现
        for(int i=1;i<=6;++i){
            B.pos=i;
            vis[B.now][i][1]=0;
            q.push(B);
        }
        printf("%d\n",TWBFS());
        return 0;
    }
    

    end.

    • 1

    信息

    ID
    915
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者