1 条题解
-
0
自动搬运
来自洛谷,原作者为

cqbzlym
自见者不明,自是者不彰搬运于
2025-08-24 21:32:13,当前版本为作者最后更新于2021-02-15 12:25:00,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
本题可以采用双向BFS,
别名大模拟。原因是本题的反向搜索方式与正向相同,也就是说存在反向搜索的方式。
cqbzljsqwq大巨佬的双向BFS强悍的八维数组状态本蒟蒻学不来QwQ蒟蒻的当前状态就是一个六位数,直接扔到下标里面标记。
那么很明显,用六位数比用字符串做状态快了无数倍,同时也会麻烦无数倍。
比如,本人程序一直很慢的原因是:有超过两小时的时间一直认为存六位数的下标应该开
1e7的数组,()导致memset直接爆炸。设计状态:
struct node{ int now;//当前的六位数密码 int stp;//当前所用步数 int pos;//当前光标所在位置 bool flag;//搜索方向,0表示正向,1表示反向 }left/right操作好说,直接改变pos的值就行了。但
up/down和swap0/swap1是要改变now的某几位上的值,很麻烦。我们先存储一个数从左向右每一位对应的单位:
const int ws[]={1000000,100000,10000,1000,100,10,1}; //防RE,第0位也要存假设我们要将
num在pos上的值更改为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
- 上传者