双向广搜还是一个很神奇的东西
//判重更神奇;
双广仅适用于有目标状态的题目;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
#include<cmath>
#include<map>
#include<set>
using namespace std;
const int maxx=362880 + 5;
const int mo=1e6+7;
struct rec{
int tu[4][4];
int x,y;
}q[maxx/2];
int b[4][4]={{0,0,0,0},{0,1,2,3},{0,8,0,4},{0,7,6,5}};
int zx[5]={0,1,0,0,-1},
zy[5]={0,0,1,-1,0};
int vis[1000007],dis[1000007];
int h=0,t=1;
int incode(int x)
{
long long ans=0;
for(int i=3;i>=1;i--)
{
for(int j=3;j>=1;j--)
{
ans=ans*10+q[x].tu[i][j];
}
}
return ans%mo;
}
void bfs()
{
vis[incode(1)]=1;
vis[incode(2)]=2;
t++;
while(h<=t)
{
h++;
int ct=incode(h);
int nt;
for(int i=1;i<=4;i++)
{
int nx=q[h].x,ny=q[h].y;
int tx=nx+zx[i],ty=ny+zy[i];
if(tx<4&&ty<4&&tx>0&&ty>0)
{
t++;
q[t]=q[h];
swap(q[t].tu[tx][ty],q[t].tu[nx][ny]);
if(!vis[nt=incode(t)])
{
vis[nt]=vis[ct];
dis[nt]=dis[ct]+1;
q[t].x=tx,q[t].y=ty;
//if(vis[nt]==1) show(t);
}
else if(vis[nt]!=vis[ct])
{
cout<<dis[nt]+dis[ct]+1;
return;
}
else t--;
}
}
}
}
int main()
{
//ios::sync_with_stdio(false);
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
char k;
cin>>k;
int kk=k-'0';
if(!kk)q[1].x=i,q[1].y=j,q[1].tu[i][j]=0;
else q[1].tu[i][j]=kk;
q[2].tu[i][j]=b[i][j];
if(!b[i][j])q[2].x=i,q[2].y=j;
}
}
bfs();
return 0;
}
其实就是在原来的广搜队列里开始多push了一个终点状态,每次产生一个新状态的vis有两种一种是从正向拓展来的另一种是反向拓展来的,其他和正常搜一样,拓展节点的时候若vis=true判断是哪个方向来的,如果是从反方向来的那么结束搜索return dis[当前head节点]+dis[拓展到的节点]+1;
下面是普通广搜和双向广搜运行时间比较:
PS:判重真是个好东西,真得好好学;