HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)

时间:2020-12-23 10:37:36

bfs搜索加记录路径

HDOJ-1043

  • 主要思路就是使用双向广度优先搜索,找最短路径。然后记录路径,找到结果是打印出来。
  • 使用康拓序列来来实现状态的映射。
  • 打印路径推荐使用vector最后需要使用algorithm里的reverse进行路径的翻转。
  • 注意本题有多组输入,这里的输入需要注意一下。
  • 如果题目没有要求最短路径,那么使用深搜的话也可以记录路径,这里也给出了代码。
  • 这里的记录路径的方法可以学习。还有判断没有解决方案的解决,利用逆序数。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<map>
using namespace std;
const int maxn=362880;
int state[maxn][9];//从1开始
struct node{
int x;
int y;
int state;//编码
string s;
};
int fact[9];//阶乘
bool vis[maxn];
bool visr[maxn];
map<int,char> ma;
map<int,char> mar;
void init(){
fact[0]=1;
for(int i=1;i<=8;i++){
fact[i]=fact[i-1]*i;
}
ma[0]='u';mar[0]='d';
ma[1]='l';mar[1]='r';
ma[2]='d';mar[2]='u';
ma[3]='r';mar[3]='l';
}
int computeCon(string s){
int code=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++){
if(s[j]-'0'<s[i]-'0')
cnt++;
}
code+=fact[8-i]*cnt;
}
return code;
}
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
bool in(int x,int y){
return x>=0&&x<3&&y>=0&&y<3;
}
string path[maxn];//-----------------------这种记录路径的方法很好----------------------------------
void bfs(string s,string final){
memset(vis,0,sizeof(vis));
memset(visr,0,sizeof(visr));
queue<node> q;
queue<node> q1;
int sx,sy;
for(int i=0;i<9;i++){
if(state[1][i]==0){
sx=i/3;
sy=i%3;
break;
}
}
int con=computeCon(s);
vis[con]=true;
node sta=node{sx,sy,con,s};
q.push(sta);
int conr=computeCon(final);
visr[conr]=true;
q1.push(node{2,2,conr,final});
path[con]="";
path[conr]="";
while(!q.empty()){
node temp=q.front();
q.pop();
//cout<<temp.state<<endl;
// if(temp.s==final){
// //print(temp.state);
// cout<<path[temp.state]<<endl;
// return true;
// }
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
char direction=ma[i];
if(visr[nowcon]){
reverse(path[nowcon].begin(),path[nowcon].end());
cout<<path[temp.state]<<ma[i]<<path[nowcon]<<endl;
return;
}
if(!vis[nowcon]){
vis[nowcon]=1;
node now;
now.x=tx,now.y=ty,now.s=ns,now.state=nowcon;
q.push(now);
path[nowcon]=path[temp.state];
path[nowcon]+=direction;
//path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
temp=q1.front();
q1.pop();
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
char direction=mar[i];
if(vis[nowcon]){
reverse(path[temp.state].begin(),path[temp.state].end());
cout<<path[nowcon]<<mar[i]<<path[temp.state]<<endl;
return;
}
if(!visr[nowcon]){
visr[nowcon]=1;
node now;
now.x=tx,now.y=ty,now.s=ns,now.state=nowcon;
q1.push(now);
path[nowcon]=path[temp.state];
path[nowcon]+=direction;
//path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
init();
char c;
while(cin>>c){
string s="";
if(c=='x')
state[1][0]=0;
else state[1][0]=c-'0';
s+=(state[1][0]+'0');
for(int i=1;i<=8;i++){
cin>>c;
if(c=='x')
state[1][i]=0;
else state[1][i]=c-'0';
s+=(state[1][i]+'0');
}
//cout<<s<<endl;
string final="123456780";
int k=0;
for(int i=0;i<9;i++){
if(!state[1][i])
continue;
for(int j=i+1;j<9;j++){
if(state[1][j]<state[1][i]&&state[1][j]){
k++;
}
}
}
if(k&1){
cout<<"unsolvable"<<endl;
continue;
}
bfs(s,final);
}
return 0;
}

这里是未Ac超时了的代码,而且记录路径的方法没有上面好。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<map>
using namespace std;
const int maxn=362880;
int state[maxn][9];//从1开始
struct node{
int x;
int y;
int state;//编码
int father;
char direction;
string s;
};
int fact[9];//阶乘
bool vis[maxn];
map<int,char> ma;
map<string,int> conma;
void init(){
fact[0]=1;
for(int i=1;i<=8;i++){
fact[i]=fact[i-1]*i;
}
ma[0]='u';
ma[1]='l';
ma[2]='d';
ma[3]='r';
}
int computeCon(string s){
int code=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=i+1;j<9;j++){
if(s[j]-'0'<s[i]-'0')
cnt++;
}
code+=fact[8-i]*cnt;
}
return code;
}
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
bool in(int x,int y){
return x>=0&&x<3&&y>=0&&y<3;
}
node path[maxn];
void print(int state){
vector<char> v;
//cout<<state<<endl;
while(path[state].direction!='n'){
//cout<<state<<endl;
v.push_back(path[state].direction);
state=path[state].father;
}
reverse(v.begin(),v.end());
for(int i=0;i<v.size();i++){
cout<<v[i];
}
cout<<endl;
}
bool bfs(string s,string final){
memset(vis,0,sizeof(vis));
queue<node> q;
int sx,sy;
for(int i=0;i<9;i++){
if(state[1][i]==0){
sx=i/3;
sy=i%3;
break;
}
}
int con=computeCon(s);
vis[con]=true;
node sta=node{sx,sy,con,-1,'n',s};
q.push(sta);
path[con]=sta;
while(!q.empty()){
node temp=q.front();
q.pop();
//cout<<temp.state<<endl;
if(temp.s==final){
print(temp.state);
return true;
}
for(int i=0;i<4;i++){
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
int newz=tx*3+ty;
int oldz=temp.x*3+temp.y;
if(in(tx,ty)){
string ns=temp.s;
ns[newz]=temp.s[oldz];
ns[oldz]=temp.s[newz];
int nowcon=computeCon(ns);
if(!vis[nowcon]){
vis[nowcon]=1;
node now;
char direction=ma[i];
now.x=tx,now.y=ty,now.father=temp.state,now.direction=direction,now.s=ns,now.state=nowcon;
q.push(now);
path[nowcon]=now;
//cout<<now.s<<endl;
}
}
}
}
return false;
}
int main(){
init();
char c;
while(cin>>c){
string s="";
if(c=='x')
state[1][0]=0;
else state[1][0]=c-'0';
s+=(state[1][0]+'0');
for(int i=1;i<=8;i++){
cin>>c;
if(c=='x')
state[1][i]=0;
else state[1][i]=c-'0';
s+=(state[1][i]+'0');
}
//cout<<s<<endl;
string final="123456780";
if(!bfs(s,final)){
cout<<"unsolvable"<<endl;
}
}
return 0;
}