因为是出边与终点直接或间接相连,所以将边反向,从终边开始,将所有终边能到达的点都打上标记
因为是最短路,所以不需要处理重边和自环,于是再跑最短路就好
题目关键:
路径上的所有点的出边所指向的点都直接或间接与终点连通
这句话的意识也就是变相的告诉我们,对于一个点x, 他的一条出边连的点y并不能直接或间接的与终点相连,此时我们要给x打上标记
因此,我们在最初从终点开始扫的仅仅是终点能到达的,对于终点不能到达的,我们最后要单独把他们的父节点(方便理解的说法)安排上
但是如果只使用一个标记数组,会出现后效性,所以我们要使用两个标记数组
处理完后跑最短路即可
此题学会的操作:在特定时候,为了简化问题,可以将边反向
此题踩到的雷:kill是关键词,然后吃了两发ce(本来可以1A)
1 #include<bits/stdc++.h> 2 #define uint unsigned int 3 using namespace std; 4 const int maxm = 200086; 5 const int maxn = 10086; 6 struct shiki { 7 int y, net; 8 }e[maxm]; 9 int lin[maxm], len = 0; 10 int n, m, flag; 11 int s, t; 12 bool kil[maxn], vis[maxn]; 13 int dis[maxn]; 14 15 inline int read() { 16 int x = 0, y = 1; 17 char ch = getchar(); 18 while(!isdigit(ch)) { 19 if(ch == '-') y = -1; 20 ch = getchar(); 21 } 22 while(isdigit(ch)) { 23 x = (x << 1) + (x << 3) + ch - '0'; 24 ch = getchar(); 25 } 26 return x * y; 27 } 28 29 inline void insert(int xx, int yy) { 30 e[++len].net = lin[xx]; 31 e[len].y = yy; 32 lin[xx] = len; 33 } 34 35 void find_your_brother(int t) { 36 vis[t] = kil[t] = 1; 37 for(int i = lin[t]; i; i = e[i].net) 38 if(!vis[e[i].y]) find_your_brother(e[i].y); 39 } 40 41 queue<int> q; 42 inline void spfa(int st) { 43 memset(vis, 0, sizeof(vis)); 44 memset(dis, 0x3f3f3f, sizeof(dis)); 45 flag = dis[0]; 46 q.push(st); vis[st] = 0, dis[st] = 0; 47 while(!q.empty()) { 48 int k = q.front(); q.pop(); 49 vis[k] = 0; 50 for(int i = lin[k]; i; i = e[i].net) { 51 int to = e[i].y; 52 if(!kil[to]) continue; 53 if(dis[to] > dis[k] + 1) { 54 dis[to] = dis[k] + 1; 55 if(!vis[to]) { 56 vis[to] = 1; 57 q.push(to); 58 } 59 } 60 } 61 } 62 } 63 64 int main() { 65 n = read(), m = read(); 66 for(int i = 1; i <= m; ++i) { 67 int x, y; 68 x = read(), y = read(); 69 insert(y, x);//反向建边 70 } 71 s = read(), t = read(); 72 find_your_brother(t); 73 for(register uint i = 1; i <= n; ++i) { 74 if(!vis[i]) 75 for(int j = lin[i]; j; j = e[j].net) 76 if(kil[e[j].y]) kil[e[j].y] = 0; 77 } 78 spfa(t); 79 if(dis[s] >= flag) cout << -1 << ' '; 80 else cout << dis[s] << ' '; 81 return 0; 82 }