蓝桥杯 历届试题 九宫重排(bfs 状态压缩)
题意:给你两串字符问s->t需要经过多少步骤。
思路:
1、解决字符和移动,记录空格的位置,然后转为坐标形式在用dx,dy进行移动处理
2、bfs 对访问过的状态标记,状态压缩(参考刘汝佳入门经典p201)--一开始用的map标记状态,然后超时了,就改用状态压缩写,就过了,好使
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<queue>
using namespace std;
map<string, int> m;
string s,goal;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
struct node{
string st;
int bs;
node(){
}
node(string a,int b){
st=a;bs=b;
}
};
//map<string,int> mm;
int vis[362880],fact[9];
void init(){
fact[0]=1;
for(int i=1;i<9;i++) fact[i]=fact[i-1]*i;
}
int judge(string s){
int code=0;
for(int i=0;i<9;i++) if(s[i]=='.') {
s[i]='0'; break;
}
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++) if(s[i]<s[j]) cnt++;
code+=fact[8-i]*cnt;
}
if(vis[code]) return 0;
return vis[code]=1;
}
int bfs(){
init();
queue<node> q;
q.push(node(s,0));
//mm[s]=1;
while(!q.empty()){
node tmp=q.front();q.pop();
string st=tmp.st;
int dis=tmp.bs;
if(st==goal) return dis;
int z;
for(z=0;z<st.size();z++) if(st[z]=='.') break;
int x=z/3,y=z%3;
for(int i=0;i<4;i++){
int ux=x+dx[i];
int uy=y+dy[i];
int uz=ux*3+uy;
if(ux<0||uy<0||ux>=3||uy>=3) continue;
string st1=st;
st1[uz]=st[z];
st1[z]=st[uz];
if(judge(st1)) m[st1]=1,q.push(node(st1,dis+1));
}
}
return 0;
}
int main(){
cin>>s>>goal;
int ans=bfs();
if(ans) printf("%d\n",ans);
else printf("-1\n");
return 0;
}