(http://www.elijahqi.win/2017/07/05/%E3%80%90luogu1379%E3%80%91-%E5%85%AB%E6%95%B0%E7%A0%81%E9%9A%BE%E9%A2%98/)
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初试状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
输入样例#1:
283104765
输出样例#1:
4
题解:直接单向bfs会导致超时
可以考虑单向bfs为简化版 求 某一状态到另一状态的最少步数
棋盘的位置我们使用数组存储为二维
1.定义棋盘
int a[4][4]
2.定义节点
(1) 棋盘
(2)空位坐标
(3)父节点
struct node{
int a[4][4];
int x,y;
int fa;
};
3.定义队列(一维数组,存储每一个节点)
队列里头尾指针
node data[33000]
int op=0;int cl=1;
4.空位的移动方式
定义上、下、左、右偏移量
struct node1{
int x,y;
};
node1[5];
d[1].x=-1;d[1].y= 0;
d[2].x= 1;d[2].y= 0;
d[3].x= 0;d[3].y=-1;
d[4].x= 4;d[4].y= 1;
5.same(a,b)判断a棋盘和b棋盘是否相同
bool same(int a[4][4],int b[4][4]){
for(int i=1;i<=3;++i) for(int j=1;j<=3;++j) if(a[i][j]!=b[i][j]) return false;
return true;
}
6.设计函数exist(a)判断a棋盘是否在data队列中从1~cl
bool exist(int a[4][4]){
for(int i=1;i<=cl;++i) if(same(data[i].a,a)) return true;
return false;
}
7.设置函数实现a复制到b
void copy1(int a[4][4],int b[4][4]){
for(int i=1;i<=3;++i) for(int j=1;j<=3;++j) b[i][j]=a[i][j];
8.宽搜的框架
(1)将初始节点存入data[1]中
(2)
while(op<cl){
++op;
取出op对应的节点的棋盘存入a1
取出op对应的节点的空位位置 x1,y1
对棋盘a1[x1][y1] 处理上下左右生成4个新的棋盘
for(int i=1;i<=4;++i){
利用x1 y1 生成x2 y2
x2=x1+d[i].x;y2=x2+d[i].y;
判断x2 y2 是否合法
if(x2<=3 and x1>=1 and y1>=1 and y2<=3){
利用a1生成a2
copy1(a1,a2);
a2[x1][y1]=a2[x2][y2];
a2[x2][y2]=0;
判断a2是否在data中
if(!exist(a2)){
++cl;
a2存入data数组中的cl位置上
copy1(a2,data[cl].a);
data[cl].x=x2;
data[c1].y=y2;
data[cl].fa=op;
判断a2是否是目标
if(same(a2,f1)){
输出
}
}
}
}
return 0;
}
9.输出函数
void printf(){
int t=0;
//计数器记录方案的每一步
while(cl>0){
ans[++t]=cl;
cl=data[cl].fa;
}
for(int i=t;i>=1;--i) printf("%d",ans[i]);
输出ans[i] 位置的棋盘
print1(data[ans[i]].a);
}
void print1(int a[4][4]){
for(int i=1;i<=3;++i){
for(int j=1;j<=3;++i) printf("%d",a[i][j]);
print("\n");
}
}
正解:hash+单向bfs 如果比较省事可以考试stl中的map或者set 我尝试过 只有在大牛分站开o2优化(大牛分站只要提交全部都o2优化)是可以过的
看到其他blog中有使用A*或者IDA* 膜一下ORZ 还没学
a数组用来统计0从右到左第一次出现的位置 q 表示这个bfs队列
提早初始化p数组 用来储存10^x 方便取位计算
solve函数表示 solve(x,y)表示 从y的位置移动到x的位置
#include <cstdio>
#include <cstring>
#define terminal 123804765
#define N 402880 //362880=9!
#define M 1999993
#define N1 2200000
int q[N],now,nows,op,cl,d[N],p[20],a[N],st;
struct node{
int head[N1];
int size;
int state[N];
int next[N];
void init(){
size=0;memset(head,-1,sizeof(head));
}
inline void insert(int x){
int h=x%M;
state[size]=x;next[size]=head[h];head[h]=size++;
}
inline bool find(int x){
int h=x%M;
for (int i=head[h];i!=-1;i=next[i]){
if (state[i]==x) return true;
}
return false;
}
}hash;
bool solve(int i,int j){
int tmp=nows-nows/p[j]%10*p[j]+nows/p[j]%10*p[i];
//printf("%d\n",tmp);
if (!hash.find(tmp)){
if (tmp==terminal){
printf("%d",++d[op]);return true;
}
hash.insert(tmp);
a[++cl]=j;
q[cl]=tmp;
d[cl]=d[op]+1;
}
return false;
}
void init(){
p[1]=1;
for (int i=2;i<=10;++i) p[i]=p[i-1]*10;
}
int main(){
freopen("1379.in","r",stdin);
freopen("1379.out","w",stdout);
scanf("%d",&st);
init();q[1]=st;
for (int i=1;i<=9;++i){
if (st%10==0){a[1]=i;break;}
st/=10;
}
op=0,cl=1;
hash.init();
while (op<cl){
now=a[++op],nows=q[op];
if (now%3) {bool ff=solve(now,now+1); if (ff) return 0; }
if ((now-1)%3) {bool ff=solve(now,now-1); if (ff) return 0; };
if (now<7) {bool ff=solve(now,now+3); if (ff) return 0; };
if (now>3) {bool ff=solve(now,now-3); if (ff) return 0; };
}
return 0;
}
bfs+set
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
string start,end="123804765";
set <string> v;//某状态是否被访问
string q[1000001],fx[9]={"13","024","15","046","1357","248","37","468","57"};
int ql,qr,t[1000001];
void bfs(){
while (qr>ql){
string s=q[ql]; int temp=t[ql],begin=s.find("0",0); ql++;
for (int i=0;i<fx[begin].size();i++){
int next=fx[begin][i]-48;string ss=s;
char tt=ss[begin]; ss[begin]=ss[next]; ss[next]=tt;
if (ss==end) {printf("%d",temp+1); return;}
if (v.count(ss)==0){//count 是返回元素个数,因为set里一个元素只出现一次,所以可一理解成count=1时,该情况已被访问
q[qr]=ss;t[qr]=temp+1;qr++;v.insert(ss);
}
}
}
return;
}
int main(){
cin>>start;
if (start==end) printf("0");
q[qr]=start;t[qr]=0;qr++;v.insert(start);
bfs();
return 0;
}
双向bfs
#include <cstdio>
#include <cstring>
int const N=362881;
int x1,y1,x2,y2,k,cl1,cl2,x,y,t,h,g,z,p;
int st[5][5],fi[5][5],a[5][5],f[110000];
struct node1{
int a[5][5];
int x,y;
int dep;
int ch;
int fa;
};
node1 data1[N],data2[N];
struct node2{
int s,t;
};
node2 h1[110],h2[110];
struct node3{
int x,y;
};
node3 d[5];
inline bool same(int a[5][5],int b[5][5]){
for(int i=1;i<=4;++i)
for(int j=1;j<=4;++j)
if(a[i][j]!=b[i][j]) return false;
return true;
}
inline void copy(int a[5][5],int b[5][5]){
for(int i=1;i<=4;++i)
for(int j=1;j<=4;++j)
b[i][j]=a[i][j];
return ;
}
inline bool exist11(int a[5][5],int k){
int z=1;
if(k<3) z=1;
else z=h1[k-2].s;
for(int i=z;i<=h1[k].t;++i){
if(same(a,data1[i].a)) return true;
}
return false;
}
inline bool exist21(int a[5][5],int k){
int z=1;
if(k<3) z=1;
else z=h2[k-2].s;
for(int i=z;i<=h2[k].t;++i){
if(same(a,data2[i].a)) return true;
}
return false;
}
inline int exist12(int a[5][5],int k){
for(int i=h2[k].s;i<=h2[k].t;++i)
if(same(a,data2[i].a)) return i;
return 0;
}
inline int exist22(int a[5][5],int k){
for(int i=h1[k].s;i<=h1[k].t;++i)
if(same(a,data1[i].a)) return i;
return 0;
}
void print(){
int ans1[110000];
int t1=0;
int p1=data1[cl1].fa;
while(p1>0){
ans1[++t1]=data1[p1].ch;
p1=data1[p1].fa;
}
for(int i=t1-1;i>=1;--i){
if(ans1[i]==1) printf("u");
if(ans1[i]==2) printf("d");
if(ans1[i]==3) printf("l");
if(ans1[i]==4) printf("r");
}
int ans2[110000];
int t2=0;
int p2=data2[cl2].fa;
while(p2>0){
ans2[++t2]=data2[p2].ch;
p2=data2[p2].fa;
}
for(int i=t2-1;i>=1;--i){
if(ans2[i]==1) printf("d");
if(ans2[i]==2) printf("u");
if(ans2[i]==3) printf("r");
if(ans2[i]==4) printf("l");
}
return ;
}
int main(){
// freopen("ex11.in","r",stdin);
for(int i=1;i<=3;++i)
for(int j=1;j<=3;++j){
scanf("%c",&st[i][j]);
if(st[i][j]!='0'){
st[i][j]-='0';
}
if(st[i][j]=='0'){
st[i][j]=0;
x1=i;y1=j;
}
}
/*for(int i=1;i<=3;++i){
for(int j=1;j<=3;++j){
printf("%d ",st[i][j]);
}
printf("\n");
}*/
fi[1][1]=1;fi[1][2]=2;fi[1][3]=3;
fi[2][1]=8;fi[2][2]=0;fi[2][3]=4;
fi[3][1]=7;fi[3][2]=6;fi[3][3]=5;
x2=2;y2=2;
if(same(st,fi)){
printf("0");
return 0;
}
d[1].x=-1;d[1].y= 0;
d[2].x= 1;d[2].y= 0;
d[3].x= 0;d[3].y=-1;
d[4].x= 0;d[4].y= 1;
copy(st,data1[1].a);
data1[1].dep=0;
data1[1].fa=0;
data1[1].ch=0;
data1[1].x=x1;data1[1].y=y1;
cl1=1;
h1[1].s=1;h1[1].t=1;
copy(fi,data2[1].a);
data2[1].dep=0;
data2[1].fa=0;
data2[1].ch=0;
data2[1].x=x2;data2[1].y=y2;
cl2=1;
h2[1].s=1;h2[1].t=1;
k=1;
while(h1[k].s<=h1[k].t and h2[k].s<=h2[k].t){
h1[k+1].s=h1[k].t+1;
for(int op=h1[k].s;op<=h1[k].t;++op){
for(int i=1;i<=4;++i){
x=data1[op].x+d[i].x;y=data1[op].y+d[i].y;
if(x>0 and x<4 and y>0 and y<4){
copy(data1[op].a,a);
a[data1[op].x][data1[op].y]=a[x][y];
a[x][y]=0;
if(!exist11(a,k)){
++cl1;
copy(a,data1[cl1].a);
data1[cl1].dep=data1[op].dep+1;
data1[cl1].ch=i;
data1[cl1].fa=op;
data1[cl1].x=x;data1[cl1].y=y;
t=exist12(a,k);
if(t){
printf("%d\n",data1[cl1].dep+data2[t].dep);
//print();
/*h=cl1;
while (data1[h].fa>0){
++g;
f[g]=data1[h].ch;
h=data1[h].fa;
}
for (int j=g;j>=1;--j){
if (f[j]==1) printf("u");
if (f[j]==2) printf("d");
if (f[j]==3) printf("l");
if (f[j]==4) printf("r");
//printf("%c",w[f[j]]);
}
h=t;
while (data2[h].fa>0){
if (data2[h].ch==1) printf("d");
if (data2[h].ch==2) printf("u");
if (data2[h].ch==3) printf("r");
if (data2[h].ch==4) printf("l");
//printf("%c",w[5-data2[h].ch]);
h=data2[h].fa;
}*/
return 0;
}
}
}
}
}
h1[k+1].t=cl1;
h2[k+1].s=h2[k].t+1;
for(int op=h2[k].s;op<=h2[k].t;++op){
for(int i=1;i<=4;++i){
x=data2[op].x+d[i].x;y=data2[op].y+d[i].y;
if(x>0 and x<4 and y>0 and y<4){
copy(data2[op].a,a);
a[data2[op].x][data2[op].y]=a[x][y];
a[x][y]=0;
if(!exist21(a,k)){
++cl2;
copy(a,data2[cl2].a);
data2[cl2].dep=data2[op].dep+1;
data2[cl2].ch=i;
data2[cl2].fa=op;
data2[cl2].x=x;data2[cl2].y=y;
t=exist22(a,k+1);
if(t){
printf("%d\n",data2[cl2].dep+data1[t].dep);
//print();
/*h=cl1;
while (data1[h].fa>0){
++g;
f[g]=data1[h].ch;
h=data1[h].fa;
}
for (int j=g;j>=1;--j){
if (f[j]==1) printf("u");
if (f[j]==2) printf("d");
if (f[j]==3) printf("l");
if (f[j]==4) printf("r");
}
h=t;
while (data2[h].fa>0){
if (data2[h].ch==1) printf("d");
if (data2[h].ch==2) printf("u");
if (data2[h].ch==3) printf("r");
if (data2[h].ch==4) printf("l");
h=data2[h].fa;
}*/
return 0;
}
}
}
}
}
h2[k+1].t=cl2;
k+=1;
}
return 0;
}