由于本题有一个条件是“路径上的所有点的出边所指向的点都直接或间接与终点连通”,所以可以先从终点开始(倒着存边)用 bfs搜一遍,把每个可以从终点到达的点标记一下,然后把能直接到达未被标记的点的那些点也给添加标记。
注意(非常非常重要!!!):这里用另一个vis数组标记,因为这里的标记有后效性,会把能间接到达未被标记的点的那些点也标记上。之后再进行一次bfs,记录最短路径长度。
具体看代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,s,t,d[20000],xx[20000],a,to[300000],next[300000],head[300000];
bool f[20000],z[20000],vis[20000];
void bfs1(int x)
{
int h=0,t=1;
d[1]=x; f[x]=1;
while(h<t)
{
h++; x=d[h]; z[x]=1;
for(int i=head[x];i>0;i=next[i])
if(f[to[i]]==0)
{
f[to[i]]=1;
t++;
d[t]=to[i];
}
}
}
void bfs2(int x)
{
int h=0,t=1;
d[1]=x; f[x]=1;
while(h<t)
{
h++; x=d[h];
for(int i=head[x];i>0;i=next[i])
{
if(z[to[i]]==0||f[to[i]]==1) continue;
f[to[i]]=1;
t++;
d[t]=to[i];
xx[to[i]]=xx[x]+1;
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>to[i]>>a; //倒存边。
next[i]=head[a];
head[a]=i;
}
cin>>s>>t;
bfs1(t);
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) vis[i]=z[i]; //用另一个数组存非常关键!!!
for(int i=1;i<=n;i++)
if(vis[i]==0)
for(int j=head[i];j>0;j=next[j])
z[to[j]]=0;
bfs2(t); //由于是存倒边,所以只能从终点开始。
if(xx[s]==0) cout<<"-1";
else cout<<xx[s];
return 0;
}