题目描述
在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。
2 .在满足条件1 的情况下使路径最短。
注意:图G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入输出格式
输入格式:输入文件名为road .in。
第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边。
接下来的m 行每行2 个整数x 、y ,之间用一个空格隔开,表示有一条边从点x 指向点y 。
最后一行有两个用一个空格隔开的整数s 、t ,表示起点为s ,终点为t 。
输出格式:输出文件名为road .out 。
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出- 1 。
输入输出样例
3 2 1 2 2 1 1 3
-1
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5
3
说明
对于30%的数据,0<n≤10,0<m≤20;
对于60%的数据,0<n≤100,0<m≤2000;
对于100%的数据,0<n≤10,000,0<m≤200,000,0<x,y,s,t≤n,x≠t。
分析
【瞎扯】
题目都没看仔细就把这题当成最短路模板做了,一边做还一边想,这种模板题居然还【普及+/提高-】,还被老师拿出来给我们做。
写完发现样例过不了,然后一看样例解释的图片就懵了。这个样例有问题啊喂,最短路明明是2,怎么会是3?然后接着往下看就更懵了,
注意:点2不能在答案路径中,因为点2连了一条边到点6,而点6不与终点5连通。
这啥玩意儿,我怎么不知道还有这个规则,然后回过头去看题目的条件1。好吧我没看见。【服了!】
【正经】
扯完了,来说这个条件1究竟改怎么对付。我们要找到那些不符合条件1的点,也就是在其出边中至少有一条不能到达终点。怎么解决呢?
建立反图。从终点开始往回跑BFS,不能搜到的点及与其直接相连的点就是不符合条件1的点。样例2中,点6不能被搜到,点2是与其直接相连的点,所以这两个点是要被删除的。
然后就正着跑SPFA啦!
程序
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int MAXN = 10000 + 1, MAXM = 200000 + 1; 4 int n, m, s, t, Head[MAXN], rH[MAXN], EdgeCount; 5 bool vis[MAXN], bad[MAXN]; 6 // vis[i]表示i点能否反向BFS搜到 7 // bad[i]表示是否不符合条件1的点 8 struct edge 9 { 10 int Next, Aim; 11 }Edge[MAXM], rev[MAXM]; 12 // 分别是原图和反图 13 void insert(int u, int v) 14 { 15 Edge[++EdgeCount] = edge{Head[u], v}; 16 rev[EdgeCount] = edge{rH[v], u}; 17 rH[v] = Head[u] = EdgeCount; 18 } 19 // 建立原图和反图 20 void BFS(int p) 21 { 22 for (int i = rH[p]; i; i = rev[i].Next) 23 if (vis[rev[i].Aim]) 24 continue; 25 else 26 vis[rev[i].Aim] = true, BFS(rev[i].Aim); 27 } 28 int SPFA() 29 { 30 queue<int> Q; 31 int dist[MAXN]; 32 memset(dist, 0x3F, sizeof(dist)); 33 dist[s] = 0; 34 Q.push(s); 35 while (!Q.empty()) 36 { 37 int u = Q.front(); 38 Q.pop(); 39 for (int i = Head[u]; i; i = Edge[i].Next) 40 { 41 int v = Edge[i].Aim; 42 if (bad[v]) 43 continue; 44 // ↑不满足条件1直接continue 45 if (dist[u] + 1 < dist[v]) 46 { 47 Q.push(v); 48 dist[v] = dist[u] + 1; 49 } 50 } 51 } 52 if (dist[t] == 0x3F3F3F3F) 53 return -1; 54 else 55 return dist[t]; 56 } 57 int main() 58 { 59 freopen("road.in","r",stdin); 60 freopen("road.out","w",stdout); 61 cin >> n >> m; 62 for (int i = 1; i <= m; i++) 63 { 64 int u, v; 65 cin >> u >> v; 66 insert(u,v); 67 } 68 cin >> s >> t; 69 vis[t] = true; 70 BFS(t); 71 // ↑反向BFS搜索不与终点相连的点 72 // ↓枚举vis[i],若vis[i]为假,那么i不与终点相连 73 // 枚举在反图当中以i为起始点的所有边的终点,这些点都不能满足条件1 74 for (int i = 1; i <= n; i++) 75 if (!vis[i]) 76 { 77 for (int j = rH[i]; j; j = rev[j].Next) 78 bad[rev[j].Aim] = true; 79 bad[i] = true; 80 } 81 cout << SPFA() << endl; 82 return 0; 83 }