NOIP TG 2014 寻找道路 【SPFA】

题目描述

在有向图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 。

输入输出样例

输入样例#1:
3 2
1 2
2 1
1 3
输出样例#1:
-1
输入样例#2:
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
输出样例#2:
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 }

 

posted @ 2018-02-11 21:45  OptimusPrime_L  阅读(145)  评论(0编辑  收藏  举报