在信息竞赛中,常常会遇到一些用广度优先搜索才能实现的题目,而这类题目很大一部分都可以用双向宽搜来提高搜索速度,
这类题目的共同点是:
1。 起始状态和目标状态都很明确;
2。 搜索一条从起始状态道目标状态的最短路径。
3。 规则具有对称性,既如果原规则向左,则其相反规则就是向右,双向时,从目标状态像起始状态搜索时,需要将规则对称。
双向宽搜的思路为分别以目标状态和初始状态为起点,分别扩展节点,当扩展到相同的节点时,就找到了目标,最短路径为起始状态和目标状态到搜索到的点的路径之和。下面附图
具体实现过程如下(C++党老老实实的手打队列吧哈哈)
int head[2],tail[2],queue[maxn][2],ji[maxn][2];
void checkmeet(int t)
{
检查新扩展的节点是否在另一个搜索状态中出现过;
出现过:输出并退出程序;
}
void expand(int t)
{
head[t]++;
for(按规则扩展)
{
判重;
入队;
checkmeet(t); //检查是否相遇
}
}
void DoubleBFS()
{
head[0]=;tail[0]=;
head[1]=;tail[1]=;
queue[1][1]=目标状态;
queue[0][1]=起始状态;
ji[1][1]=;
ji[0][1]=; //初始化
while(head[0]<tail[0]&&head[1]<tail[1])
{
if(tail[0]<tail[1])
expand(0);
else
expand(1);
}
}
#include<cstdio>
#include<iostream>
#include<set>
#include<string.h>
#include <cstdlib>
using namespace std;
string st,en;
int ans,head[2],tail[2];
string s[100005][2];
int b[100005][2];
set<string>hash[2];
void checkmeet(int t)
{
if(hash[1-t].count(s[tail[t]][t]))
{
for(int i=1;i<=tail[1-t];i++)
if(s[i][1-t]==s[tail[t]][t])
{
printf("%d\n",b[i][1-t]+b[tail[t]][t]);
break;
}
exit(0);
}
}
string get(string s,int i)
{
string t=s;
int lwz=s.find('0');
if(i==1)
{
if(lwz<3) return "-1";
swap(t[lwz],t[lwz-3]);
return t;
}
if(i==2)
{
if(lwz==0||lwz==3||lwz==6) return "-1";
swap(t[lwz],t[lwz-1]);
return t;
}
if(i==3)
{
if(lwz>5) return "-1";
swap(t[lwz],t[lwz+3]);
return t;
}
if(i==4)
{
if(lwz==2||lwz==5||lwz==8) return "-1";
swap(t[lwz],t[lwz+1]);
return t;
}
}
void expand(int t)
{
head[t]++;
string ss=s[head[t]][t];
int c=b[head[t]][t]+1;
for(int i=1;i<=4;i++)
{
string stmp=get(ss,i);
if(stmp=="-1"||hash[t].count(stmp))continue;
else
{
hash[t].insert(stmp);
tail[t]++;
b[tail[t]][t]=c;
s[tail[t]][t]=stmp;
checkmeet(t);
}
}
}
void DoubleBFS()
{
head[0]=0;tail[0]=1;
head[1]=0;tail[1]=1;
s[1][0]=st;
s[1][1]="123804765";
while(head[0]<tail[0]&&head[1]<tail[1])
if(tail[0]<tail[1])expand(0);else expand(1);
}
int main()
{
cin>>st;
DoubleBFS();
}