这道题可以把边都反着存一遍,从终点开始深搜,然后把到不了的点 和它们所指向的点都去掉。
最后在剩余的点里跑一遍spfa就可以了。
——代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <queue> const int maxn = 100001; int n, m, s, t, cnt1, cnt2; int dis[maxn]; int next1[4 * maxn], to1[4 * maxn], head1[4 * maxn], next2[4 * maxn], to2[4 * maxn], head2[4 * maxn]; bool vis[maxn], b[maxn], f[maxn], flag; inline void add1(int x, int y) { to1[cnt1] = y; next1[cnt1] = head1[x]; head1[x] = cnt1++; } inline void add2(int x, int y) { to2[cnt2] = y; next2[cnt2] = head2[x]; head2[x] = cnt2++; } inline void dfs(int u) { int i, v; if(u == s) flag = 1; vis[u] = 1; for(i = head2[u]; i != -1; i = next2[i]) { v = to2[i]; if(!vis[v]) dfs(v); } } inline void spfa(int u) { int i, j; std::queue <int> q; q.push(u); f[u] = 1; dis[u] = 0; while(!q.empty()) { i = q.front(); q.pop(); f[i] = 0; for(j = head1[i]; j != -1; j = next1[j]) if(!b[i] && !b[to1[j]] && dis[to1[j]] > dis[i] + 1) { dis[to1[j]] = dis[i] + 1; if(!f[to1[j]]) { f[to1[j]] = 1; q.push(to1[j]); } } } } int main() { int i, j, x, y; memset(head1, -1, sizeof(head1)); memset(head2, -1, sizeof(head2)); memset(dis, 127 / 3, sizeof(dis)); scanf("%d %d", &n, &m); for(i = 1; i <= m; i++) { scanf("%d %d", &x, &y); add1(x, y); add2(y, x); } scanf("%d %d", &s, &t); dfs(t); if(!flag) { printf("-1"); return 0; } for(i = 1; i <= n; i++) if(!vis[i]) { b[i] = 1; for(j = head2[i]; j != -1; j = next2[j]) b[to2[j]] = 1; } spfa(s); printf("%d", dis[t]); return 0; }