双向bfs
很多题目会给你起点和终点,让你求起点到终点的一条最短路径(当然这是无权图);
这时可以用bfs,但是还不是最快的方法,当知道终点时,我们可以用双向bfs;
双向和单向的区别在于,可以从终点和起点同时出发,记录每个点是被从起点开始的访问了,还是被从终点开始的访问了,如果访问到一个点,同时被起点开始的和终点开始的访问了,那么这个点就是答案的必经点,输出起终路径之和就行;
模板题一:
模板:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
#define inf 0x3f3f3f3f
//ios::sync_with_stdio(false);
using namespace std;
const int N=200100;
const int M=1000100;
const LL mod=998244353;
string s;
map<string,int>ma;
map<string,int>vis;//0表示没访问,1表示正向,2表示反向
void bfs(){
if(s=="123804765"){
cout<<0<<endl;
return;
}
queue<string>qu1,qu2;
vis[s]=1,ma[s]=0;
qu1.push(s);//正向
vis["123804765"]=2,ma["123804765"]=1;
qu2.push("123804765");//反向
while(!qu1.empty()&&!qu2.empty()){
int flag=0;
string p;
if(qu1.size()<qu2.size()){//谁结点少,先访问谁
p=qu1.front();
qu1.pop();
flag=1;
}
else{
p=qu2.front();
qu2.pop();
flag=2;
}
int d;//0的位置
for(int i=0;i<p.length();i++){
if(p[i]=='0'){
d=i;
break;
}
}
int x=d/3;
int y=d%3;
if(x>0){
string q=p;
char c=q[d];
q[d]=q[3*(x-1)+y];
q[3*(x-1)+y]=c;
if(vis[q]==0){
vis[q]=flag;
ma[q]=ma[p]+1;
if(flag==1) qu1.push(q);
else qu2.push(q);
}
else if(vis[q]+vis[p]==3){
cout<<ma[p]+ma[q]<<endl;
return;
}
}
if(x<2){
string q=p;
char c=q[d];
q[d]=q[3*(x+1)+y];
q[3*(x+1)+y]=c;
if(vis[q]==0){
vis[q]=flag;
ma[q]=ma[p]+1;
if(flag==1) qu1.push(q);
else qu2.push(q);
}
else if(vis[q]+vis[p]==3){
cout<<ma[p]+ma[q]<<endl;
return;
}
}
if(y>0){
string q=p;
char c=q[d];
q[d]=q[3*x+y-1];
q[3*x+y-1]=c;
if(vis[q]==0){
vis[q]=flag;
ma[q]=ma[p]+1;
if(flag==1) qu1.push(q);
else qu2.push(q);
}
else if(vis[q]+vis[p]==3){
cout<<ma[p]+ma[q]<<endl;
return;
}
}
if(y<2){
string q=p;
char c=q[d];
q[d]=q[3*x+y+1];
q[3*x+y+1]=c;
if(vis[q]==0){
vis[q]=flag;
ma[q]=ma[p]+1;
if(flag==1) qu1.push(q);
else qu2.push(q);
}
else if(vis[q]+vis[p]==3){
cout<<ma[p]+ma[q]<<endl;
return;
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin>>s;
bfs();
return 0;
}