『题解』洛谷P2296 寻找道路

更好的阅读体验

Portal

Portal1: Luogu

Portal2: LibreOJ

Description

在有向图(mathrm G)中,每条边的长度均为(1),现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。

  2. 在满足条件(1)的情况下使路径最短。
    注意:图(mathrm G)中可能存在重边和自环,题目保证终点没有出边。 请你输出符合条件的路径的长度。

Input

第一行有两个用一个空格隔开的整数(n)(m),表示图有(n)个点和(m)条边。

接下来的(m)行每行(2)个整数(x, y),之间用一个空格隔开,表示有一条边从点(x)指向点(y)

最后一行有两个用一个空格隔开的整数(s, t),表示起点为(s),终点为(t)

Output

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。

如果这样的路径不存在,输出(-1)

Sample Input1

3 2
1 2
2 1
1 3

Sample Output1

-1

Sample Input2

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

Sample Output2

3

Solution

我们先看一个例子:

不妨令起点为(1),终点为(3)

这个例子的答案是(3),路径是(1 o 4 o 5 o 3)

我们可以先检验出每一个点是否能到终点。可以从终点出发,按照反向边走一遍,然后把走不到的点以及它的入边连的点都删除,像这样:

最后在跑一边(bfs)序,求出最短路就可以了。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

const int MAXN = 200005;
struct EDGE {
    int to, nxt;
} edge1[MAXN], edge2[MAXN];
int n, m, u, v, S, T, cnt1, cnt2, dis[MAXN], head1[MAXN], head2[MAXN];
bool vis[MAXN];
inline void addedge(int u, int v) {//邻接表存图
    edge1[++cnt1].to = v; edge1[cnt1].nxt = head1[u]; head1[u] = cnt1;
    edge2[++cnt2].to = u; edge2[cnt2].nxt = head2[v]; head2[v] = cnt2;//反向边
}
inline void bfs1(int cur) {
    queue<int> Q;
    Q.push(cur);
    vis[cur] = 1;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for (int i = head2[u]; ~i; i = edge2[i].nxt) {//遍历每一个点
            int v = edge2[i].to;
            if (!vis[v]) {
                vis[v] = 1;
                Q.push(v);
            }
        }
    }
}
inline bool check(int u) {//判断是否能到达终点
    for (int i = head1[u]; ~i; i = edge1[i].nxt)
        if (!vis[edge1[i].to]) return 0;
    return 1;
}
inline bool bfs2(int cur) {
    queue<int> Q;
    Q.push(cur);
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        if (!check(u)) continue;
        for (int i = head1[u]; ~i; i = edge1[i].nxt) {//遍历每一个点
            int v = edge1[i].to;
            if (dis[v] == -1) {
                dis[v] = dis[u] + 1;
                Q.push(v);
                if (v == T) {
                    printf("%d
", dis[T] + 1);
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main() {
    scanf("%d%d", &n, &m);
    memset(head1, -1, sizeof(head1));
    memset(head2, -1, sizeof(head2));
    for (int i = 1; i <= m; i++) {
        scanf("%d%d", &u, &v);
        addedge(u, v);//加边
    }
    scanf("%d%d", &S, &T);
    bfs1(T);//求出终点能到的点
    memset(dis, -1, sizeof(dis));
    if (!bfs2(S)) printf("-1
");
    return 0;
}

Attachment

测试数据下载:https://www.lanzous.com/i5qa0pg

原文地址:https://www.cnblogs.com/shenxiaohuang/p/11405003.html