题目链接
题目描述
在一个有向无权图中,给定一个起始点,求它到图中所有顶点的最短路径长度。
解题思路
对于边权全部相等(或无权,可视为边权为1)的图,求解单源最短路径问题最适合使用广度优先搜索 (BFS)。
广度优先搜索 (BFS)
BFS 算法的特点是逐层遍历。它从源点开始,首先探索所有距离为 1 的邻居,然后是所有距离为 2 的邻居,以此类推。这种按距离逐层扩展的搜索方式,天然地保证了当算法第一次到达某个顶点时,所经过的路径就是从源点到该顶点的最短路径。
算法流程
-
数据结构:
- 一个队列,用于存储待访问的顶点。
- 一个邻接表
adj
,用于存储图的结构。 - 一个距离数组
dist
,用于存储源点到每个顶点的最短距离,并兼作访问标记。
-
初始化:
- 将
dist
数组的所有元素初始化为一个特殊值(例如-1
),表示所有顶点尚未被访问。 - 将源点
s
的距离dist[s]
设为0
。 - 将源点
s
推入队列。
- 将
-
搜索过程:
- 当队列不为空时,循环执行以下操作:
a. 从队列中取出一个顶点
u
。 b. 遍历u
的所有邻接点v
。 c. 如果v
尚未被访问(即dist[v] == -1
),则: i. 更新v
的距离:dist[v] = dist[u] + 1
。 ii. 将v
推入队列。
- 当队列不为空时,循环执行以下操作:
a. 从队列中取出一个顶点
-
结束:
- 当队列为空时,搜索结束。
dist
数组中就包含了从源点到所有可达顶点的最短路径长度。对于不可达的顶点,其距离值仍为初始值-1
。
- 当队列为空时,搜索结束。
代码
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m, s;
cin >> n >> m >> s;
vector<vector<int>> adj(n + 1);
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
}
vector<int> dist(n + 1, -1);
queue<int> q;
dist[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : adj[u]) {
if (dist[v] == -1) {
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
for (int i = 1; i <= n; ++i) {
cout << dist[i] << (i == n ? "" : " ");
}
cout << "\n";
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int s = sc.nextInt();
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i <= n; i++) {
adj.add(new ArrayList<>());
}
for (int i = 0; i < m; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
adj.get(u).add(v);
}
int[] dist = new int[n + 1];
Arrays.fill(dist, -1);
Queue<Integer> q = new LinkedList<>();
dist[s] = 0;
q.offer(s);
while (!q.isEmpty()) {
int u = q.poll();
for (int v : adj.get(u)) {
if (dist[v] == -1) {
dist[v] = dist[u] + 1;
q.offer(v);
}
}
}
for (int i = 1; i <= n; i++) {
System.out.print(dist[i] + (i == n ? "" : " "));
}
System.out.println();
}
}
import sys
from collections import deque
def main():
input = sys.stdin.readline
n, m, s = map(int, input().split())
adj = [[] for _ in range(n + 1)]
for _ in range(m):
u, v = map(int, input().split())
adj[u].append(v)
dist = [-1] * (n + 1)
q = deque()
dist[s] = 0
q.append(s)
while q:
u = q.popleft()
for v in adj[u]:
if dist[v] == -1:
dist[v] = dist[u] + 1
q.append(v)
print(*dist[1:])
if __name__ == "__main__":
main()
算法及复杂度
- 算法:广度优先搜索 (Breadth-First Search, BFS)
- 时间复杂度:
,其中
是顶点数,
是边数。因为每个顶点和每条边最多被访问一次。
- 空间复杂度:
,主要用于存储邻接表。距离数组和队列的空间复杂度为
。