本文介绍一种最常用的求单源最短路的算法 Dijkstra。例题:洛谷 P4779 【模板】单源最短路径(标准版)。
1. 邻接矩阵 + 朴素 Dijkstra
点的个数为 n,边的个数为 m。该算法的时间复杂度为 \(O(n^2)\),对于这道题会超时。空间复杂度为 \(O(n^2)\)。
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m, s;
cin >> n >> m >> s;
// 初始化邻接矩阵
vector g(n, vector<int>(n, INT_MAX / 2));
// 读入边并保留最小边权
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
g[u - 1][v - 1] = min(g[u - 1][v - 1], w);
}
// Dijkstra算法
vector<int> dis(n, INT_MAX / 2);
vector<int> vis(n);
dis[s - 1] = 0;
while (true) {
int x = -1;
for (int i = 0; i < n; i++) {
if (vis[i] == 0 && (x < 0 || dis[i] < dis[x])) {
x = i;
}
}
if (x < 0 || dis[x] == INT_MAX / 2) {
break;
}
vis[x] = 1;
for (int y = 0; y < n; y++) {
dis[y] = min(dis[y], dis[x] + g[x][y]);
}
}
// 输出结果
for (int i = 0; i < n; i++) {
cout << (dis[i] < INT_MAX / 2 ? dis[i] : INT_MAX) << " ";
}
cout << "\n";
return 0;
}
2. 邻接表 + 堆优化的 Dijkstra
时间复杂度为 \(O(m\log m)\),空间复杂度为 \(O(m)\)。
#include <climits>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int INF = 0x7fffffff;
int main() {
int n, m, s;
cin >> n >> m >> s;
// 初始化邻接表
vector<vector<pair<int, int>>> g(n);
// 读入边并保留最小边权
for (int i = 0; i < m; ++i) {
int u, v, w;
cin >> u >> v >> w;
g[u - 1].emplace_back(v - 1, w);
}
// Dijkstra算法
vector<int> dis(n, INF);
dis[s - 1] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>>
pq;
pq.emplace(0, s - 1);
while (!pq.empty()) {
auto [dx, x] = pq.top();
pq.pop();
if (dx > dis[x]) {
continue;
}
for (auto &[y, d] : g[x]) {
int new_dis = dx + d;
if (new_dis < dis[y]) {
dis[y] = new_dis;
pq.emplace(new_dis, y);
}
}
}
// 输出结果
for (int i = 0; i < n; ++i) {
cout << dis[i] << " ";
}
cout << "\n";
return 0;
}