• 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 }
  • 相关阅读:
    webpack配置
    gulp-babel 取消严格模式方法
    时间线
    tojson
    [[],[],[]]这样的数据转化成[{},{},{}]
    BUGFREE的安装
    Linux 打包压缩与搜索命令
    Linux 文件目录管理命令
    Linux 文本文件编辑命令
    Linux 工作目录切换命令
  • 原文地址:https://www.cnblogs.com/OIerPrime/p/8443283.html
Copyright © 2020-2023  润新知