寻找道路

链接: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。
示例1

输入

复制
3 2
1 2
2 1
1 3

输出

复制
-1

说明

如上图所示,箭头表示有向道路,圆点表示城市。起点1与终点3不连通,所以满足题目描述的路径不存在,故输出-1。

示例2

输入

复制
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

输出

复制
3

说明

如上图所示,满足条件的路径为1->3->4->5。注意点2不能在答案路径中,因为点2连了一条边到点6,而点6不与终点5连通。

备注:

对于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 }

第一次写是看了题解写出来的,然后在今天再次刷一次,但还需要巩固

posted @ 2019-10-14 14:48  PYozo_free  阅读(153)  评论(0编辑  收藏  举报