banner

原题链接

https://www.luogu.com.cn/problem/P2296

解题思路

读入图时建立正向边和反向边,两次DFS标记所有合法的点,再进行一遍BFS求最短路径。

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#define N 10001
using namespace std;
int n,m,t1,t2,s,t,d[N];
bool vis[N],go1[N],go2[N],go[N],inq[N];
vector<int> gt[N],g[N];
queue<int> q;
void dfs1(int x)
{
vis[x]=1;
for(int i=0;i<gt[x].size();i++)
{
int to=gt[x][i];
if(go1[x])go1[to]=1;
if(vis[to])continue;
dfs1(to);
}
}
void dfs2(int x)
{
vis[x]=1;
for(int i=0;i<g[x].size();i++)
{
int to=g[x][i];
if(go2[x])go2[to]=1;
if(vis[to])continue;
dfs2(to);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&t1,&t2);
if(t1==t2)continue;
gt[t2].push_back(t1);//反向建图
g[t1].push_back(t2);//正向建图
}
scanf("%d%d",&s,&t);
go1[t]=go2[t]=1;
d[t]=-1;
dfs1(t);//dfs反向图,标记和终点反向联通的点
memset(vis,0,sizeof(vis));
dfs2(t);//dfs正向图,标记和终点正向联通的点
for(int i=1;i<=n;i++)//标记所有合法点
{
if(!go1[i]&&!go2[i])continue;
go[i]=1;
for(int j=0;j<g[i].size();j++)
{
int to=g[i][j];
if(!go1[to]&&!go2[to])
{
go[i]=0;
break;
}
}
}
q.push(s);
inq[s]=1;
while(!q.empty())//bfs正向图,得最短路径
{
int now=q.front();
q.pop();
for(int i=0;i<g[now].size();i++)
{
int to=g[now][i];
if(inq[to]||!go[to])continue;
q.push(to);
inq[to]=1;
d[to]=d[now]+1;
}
}
printf("%d",d[t]);
return 0;
}