分析
关键并不在于BFS,而是在于怎么处理。
一个很显然的思路,就是我们要处理出所有能走的点。不妨从反面思考,哪些点不能走。一种是自己本身就与终点不连通,也就是说走到这个点就不可能到终点的,不能走。另一种是第一种点所有出边连的点,都不能走。这样子处理起来就比正向思考要好实现得多。
我们先建一个反图,从终点开始BFS到所有能到达的点标记起来。(这是一个非常重要判断能到达的技巧,比每个点都BFS走到终点好得多)然后对于每个这种点遍历所有出边,于是我们就找到了所有不能走的点,能走的点也就被确定了。
对于所有能走的点做BFS,找最短的路径即可。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
queue<int> q;
struct node
{
int to,next;
}e[200010];
int n,m,s,t;
int x[200010],y[200010];
int vt[10010],visb[10010],v[10010];
//能到终点的,能合法访问的,访问过的
int dis[10010];
int hd[200010],tot;
void add(int x,int y)
{
e[++tot]=(node){y,hd[x]};
hd[x]=tot;
}
inline void rebuild()
{
memset(hd,0,sizeof(hd));
memset(e,0,sizeof(e));
tot=0;
for(int i=1;i<=m;i++) add(x[i],y[i]);
}
void bfs()
{
q.push(t);
vt[t]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=hd[x];i;i=e[i].next)
{
if(vt[e[i].to]) continue;
vt[e[i].to]=1;
q.push(e[i].to);
}
}
}
void bfs2()
{
memset(dis,0x3f,sizeof(dis));
q.push(s);
dis[s]=0;
v[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=hd[x];i;i=e[i].next)
{
if(!visb[e[i].to]||v[e[i].to]) continue;
v[e[i].to]=1;
dis[e[i].to]=dis[x]+1;
q.push(e[i].to);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
add(y[i],x[i]);
}
cin>>s>>t;
bfs();
for(int i=1;i<=n;i++) visb[i]=1;
for(int i=1;i<=n;i++)
{
if(!vt[i])
{
visb[i]=0;
for(int j=hd[i];j;j=e[j].next)
visb[e[j].to]=0;
}
}
rebuild();
if(visb[s]==0)
{
cout<<-1;
return 0;
}
bfs2();
if(dis[t]==0x3f3f3f3f) cout<<-1;
else cout<<dis[t];
return 0;
}