AcWing847. 图中点的层次

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环。

所有边的长度都是 1,点的编号为 1 ~ n

请你求出 1 号点到 n 号点的最短距离,如果从 1 号点无法走到 n 号点,输出 -1

输入格式

第一行包含两个整数 nm

接下来 m 行,每行包含两个整数 ab,表示存在一条从 a 走到 b 的长度为 1 的边。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

数据范围

1 < n,m < 10^5

输入样例:

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

输出样例:

1
1

算法思想

边权为1的最短路径,考虑使用BFS.

很简单,看代码即可。
需要关注的是:

1
2
3
4
5
6
// 从起点到节点 k 的当前最短距离 dist[k] 是否大于从起点到节点 t 的距离加上 1
// 如果条件成立,说明通过节点 t 到达节点 k 的路径更短,因此需要更新 dist[k]。
if (dist[k] > dist[t] + 1) { // 更新距离
dist[k] = dist[t] + 1;
q[++tt] = k; // 将未访问的点加入队列
}

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010, M = N * 2, INF = 0x3f3f3f3f;

int n, m;
int h[N], e[M], ne[M], idx;
int dist[N];
int q[N], hh = 0, tt = -1;

void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}

int bfs(int start) {
memset(dist, 0x3f, sizeof dist); // 初始化距离数组

dist[start] = 0;
q[++tt] = start; // 将起点加入队列

while (hh <= tt) {
int t = q[hh++]; // 取出队头

for (int j = h[t]; ~j; j = ne[j]) { // 遍历所有相邻点
int k = e[j];
// 从起点到节点 k 的当前最短距离 dist[k] 是否大于从起点到节点 t 的距离加上 1
// 如果条件成立,说明通过节点 t 到达节点 k 的路径更短,因此需要更新 dist[k]。
if (dist[k] > dist[t] + 1) { // 更新距离
dist[k] = dist[t] + 1;
q[++tt] = k; // 将未访问的点加入队列
}
}
}

return dist[n] == INF ? -1 : dist[n]; // 返回终点距离或-1
}

int main() {
memset(h, -1, sizeof h); // 初始化邻接表
cin >> n >> m;

while (m--) {
int a, b;
cin >> a >> b;
add(a, b);
}

cout << bfs(1) << endl; // 输出结果

return 0;
}