Dijkstra 算法
Dijkstra 算法
后续可能会有更新……
一、算法文字说明(笔记整理)
普通堆实现的 Dijkstra 算法,时间复杂度 O(m * log m),m 为边数。
distance[i]表示从源点到i点的最短距离,visited[i]表示i节点是否从小根堆弹出过。- 准备好小根堆,小根堆存放记录:
(x点, 源点到x的距离),小根堆根据距离组织。 - 令
distance[源点] = 0,(源点, 0)进入小根堆。 - 从小根堆弹出
(u点, 源点到u的距离):- a. 如果
visited[u] == true,不做任何处理,重复步骤 4; - b. 如果
visited[u] == false,令visited[u] = true,u就算弹出过了;- 然后考察
u的每一条边,假设某边去往v,边权为w:-
- 如果
visited[v] == false并且distance[u] + w < distance[v]:
令distance[v] = distance[u] + w,把(v, distance[u] + w)加入小根堆;
- 如果
-
- 处理完
u的每一条边之后,重复步骤 4;
- 处理完
-
- 然后考察
- a. 如果
- 小根堆为空过程结束,
distance表记录了源点到每个节点的最短距离。
二、对应代码实现
结合上述步骤,对应的一份极简、清晰的 C++ 模板代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 105; // 视题目节点数范围而定
vector<vector<pair<int, int>>> a(N);
const int INF = 0x3f3f3f3f;
int main()
{
int n, m, s;
cin >> n >> m >> s;
for (int i = 1; i <= m; i ++)
{
int u, v, w;
cin >> u >> v >> w;
a[u].push_back({v, w});
}
vector<int> dist(n + 1, INF);
vector<int> vis(n + 1, 0);
// 小根堆:存放 (源点到x的距离, x点)
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
// 3. 令 distance[源点] = 0,(源点, 0) 进入小根堆
dist[s] = 0;
pq.push({0, s});
// 4. 从小根堆弹出
while (!pq.empty())
{
auto [w, u] = pq.top();
pq.pop();
// 4a. 如果 visited[u] == true,不做任何处理
if (vis[u]) continue;
// 4b. 如果 visited[u] == false,令 visited[u] = true
vis[u] = 1;
// 考察 u 的每一条边
for (auto it : a[u])
{
int v = it.first;
int weight = it.second;
// 1) 如果 visited[v] == false 并且 distance[u] + w < distance[v]
if (dist[u] + weight < dist[v])
{
// 令 distance[v] = distance[u] + w,把 (v, distance[u] + w) 加入小根堆
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
int res = 0;
for (int i = 1; i <= n; i ++)
{
if (dist[i] == INF)
{
res = -1; // 如果有不可达节点
break;
}
res = max(dist[i], res); // 这一部分是特定题目要求:求最远的最短路
}
cout << res << endl;
return 0;
}

浙公网安备 33010602011771号