寻找道路
链接:https://ac.nowcoder.com/acm/problem/16498
来源:牛客网
题目描述
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。输入描述:
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出描述:
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
示例2
备注:
对于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。
思路:首先利用反向建图和bfs,把无法直接或间接连接终点的点排除,然后在利用spfa算法,求得最短路径。(spfa算法可以求得带负值的权边)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 300000; 4 int dis[maxn], v[maxn],head[maxn], n, m, cnt; 5 bool vis[maxn], ok[maxn]; 6 struct edge { 7 int v, next; 8 }e[maxn]; //边 9 10 void add(int x, int y) //其实就是用一维数组达到领接表的一种方法 11 { 12 e[++cnt].v = y; //cnt为第几条边,而v是后继 13 e[cnt].next = head[x]; //将先前前继元素已经有的后继元素赋值给现在的后继元素 14 head[x] = cnt; //更新前继元素的后继元素 15 } 16 void spfa(int t) 17 { 18 memset(dis, 63, sizeof dis); 19 memset(vis, 0, sizeof vis); 20 queue<int>q; 21 dis[t] = 0; 22 vis[t] = 1; 23 q.push(t); //将源点让入队列中 24 while (!q.empty()) //判断队列是否为空,为空就代表找到最短路径了 25 { 26 int u = q.front(); //将队首的点pop出来,并且将其周围的点进行比较 27 q.pop(); 28 vis[u] = 0; 29 for (int i = head[u]; i; i = e[i].next) 30 { 31 int v = e[i].v; //v代表所指向的点 32 if (dis[v] > dis[u] + 1&&ok[v]) //如果这个点满足条件,就讲其放入队列中 33 { 34 if (!vis[v]) { 35 q.push(v); 36 vis[v] = 1; 37 } 38 dis[v] = dis[u] + 1; 39 } 40 } 41 } 42 } 43 44 void bfs(int t) //正常的bfs 45 { 46 memset(v, 0, sizeof v); 47 queue<int>q; 48 q.push(t); 49 ok[t] = v[t] = 1; 50 while (!q.empty()) 51 { 52 int u = q.front(); 53 q.pop(); 54 for (int i = head[u]; i; i = e[i].next) 55 { 56 int f = e[i].v; 57 if (!v[f]) 58 { 59 ok[f]=v[f] = 1; 60 q.push(f); 61 } 62 } 63 } 64 } 65 66 int main() 67 { 68 int s, t; 69 scanf("%d%d", &n, &m); 70 for (int i = 1; i <= m; i++) 71 { 72 int x, y; 73 scanf("%d%d", &x, &y); 74 add(y, x); 75 } 76 scanf("%d%d", &s, &t); 77 bfs(t); 78 for (int i = 1; i <= m; i++) 79 { 80 if (!v[i]) 81 { 82 for (int j = head[i]; j; j = e[j].next) 83 { 84 ok[e[j].v] = 0; 85 } 86 } 87 } 88 spfa(t); 89 if (dis[s] >= 1061109567) 90 { 91 printf("-1"); 92 return 0; 93 } 94 printf("%d", dis[s]); 95 }
第一次写是看了题解写出来的,然后在今天再次刷一次,但还需要巩固