NKOJ 3631 密码锁
思路
- BFS经典题。
实现方法
- 用一个结构体存储当前密码锁的状态和已经走过的步数。
- 将开始的状态入队。
- 每次取出队首,枚举所有可能情况。
- 每一位的上下拨动。
- 每两位之间的交换。
- 共 \(11\) 种情况。
- 给入队的情况打标记。
代码
#include<map>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{int n1,n2,n3,n4,stp;};
int work(node x){
return x.n1*1000+x.n2*100+x.n3*10+x.n4;
}
int mp[9999];
int change(int x){
if(x>=9) return 1;
else return x+1;
}
int shift(int x){
if(x<=1) return 9;//注意点1
else return x-1;
}
void bfs(node st,node en){
queue<node> que;
que.push(st);
while(!que.empty()){
node tp=que.front();
que.pop();
if(tp.n1==en.n1&&tp.n2==en.n2&&tp.n3==en.n3&&tp.n4==en.n4){
printf("%d",tp.stp);
return;
}
node nxt=tp;
nxt.stp++;
//1
nxt.n1=change(tp.n1);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n1=shift(tp.n1);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n1=tp.n1;
//2
nxt.n2=change(tp.n2);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n2=shift(tp.n2);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n2=tp.n2;
//3
nxt.n3=change(tp.n3);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n3=shift(tp.n3);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n3=tp.n3;
//4
nxt.n4=change(tp.n4);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n4=shift(tp.n4);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
nxt.n4=tp.n4;
//1,2
swap(nxt.n1,nxt.n2);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
swap(nxt.n1,nxt.n2);
//2,3
swap(nxt.n2,nxt.n3);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
swap(nxt.n2,nxt.n3);
//3,4
swap(nxt.n3,nxt.n4);
if(mp[work(nxt)]==0) que.push(nxt),mp[work(nxt)]=1;
swap(nxt.n3,nxt.n4);
}
}
int main(){
node st,en;
scanf("%d%d%d%d",&st.n1,&st.n2,&st.n3,&st.n4);
scanf("%d%d%d%d",&en.n1,&en.n2,&en.n3,&en.n4);
st.stp=0,en.stp=0;
bfs(st,en);
return 0;
}
本题特色
- Q:为什么状压?
- A:在打标记时原本状态较多,每一个状态如果用一个
int
存储将会光荣MLE
。 - Q:怎么压?
- A:注意到题目说每一位都在 \(1 \sim 9\) 之间。这时用能存储 \(2 \times 10^9\) 大小的
int
有亿点浪费,而一个整数的每一位刚好能存 \(1 \sim 9\) 之间的数(在保证首位不为 \(0\) 的情况下)。所以将每个状态标记转化为十进制数存储,大大节省数组空间。
注意事项
- 注意在写变换函数的时候,不要把 \(+1\) 和 \(-1\) 搞错了。