Dijkstra
Dijkstra’s Algorithm
Dijkstra 是根據邊的權重進行比較,用來找節點之間的最小路徑
注意:Dijkstra 演算法無法處理負權重
要點
除了用來儲存圖的二維陣列外
Dijkstra 演算法需要
- 距離陣列:起點到每一點的最短距離
- 優先佇列:快速尋找當前最短路徑的節點
觀念
從起點開始尋找
如果佇列裡的距離比已知的最短距離還遠,就跳過
遍歷所有與之相連的節點,比較從鎖定後的節點走還是原有的路徑比較短
如果新計算的路徑較短,則更新距離並重新放入佇列裡面
實作
初始化
dis 中,所有點的原距離,初始值設為極大值(除了起點設為 0)
pq 的 first 是距離,second 是節點編號,且排序為從小到大
1
2
vector<int> vis(n), dis(n, 0x3f3f3f3f); // n 為節點樹
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;算法
先將起點放入 pq
並將起點的距離設為 0
1
2
pq.push({0, s});
dis[s] = 0;接下來進入迴圈,直到所有連通的結點都被走訪為止
1
while (pq.size()) {先將目前路徑最短的節點取出
檢查該節點是否已經確認為最短距離
如果是就跳過
1
2
auto [d, node] = pq.top(); pq.pop();
if (d > dis[node]) continue;遍歷所有與目前路徑最短的節點 (node) 連通的節點 (u)
如果從 node 的距離加上從 node 到 u 的距離比目前 (u) 紀錄的最短路徑還小,則使其取代
且將更新過後的節點放入 pq 中
1
2
3
4
5
6
for (auto &[to_idx, to_dis] : g[node]) {
if (dis[node]+to_dis < dis[to_idx]) {
dis[to_idx] = dis[node] + to_dis;
pq.push({dis[to_idx], to_idx});
}
}}結果輸出
如果沒有拜訪過該節點,代表起點沒有與該節點連通
否則就輸出距離
1
2
if (!vis[t]) cout << "unreachable\n";
else cout << dis[t] << '\n';範例
題目:UVA 10986
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
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define WA() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define all(x) (x).begin(), (x).end()
#define sz(x) ((int)(x).size())
#define int long long
signed main() { WA();
int t;
cin >> t;
for (int c = 1; c <= t; c++) {
int n, m, s, t, a, b, w;
cin >> n >> m >> s >> t;
vector<vector<pair<int, int>>> g(n);
while (m--) cin >> a >> b >> w, g[a].push_back({b, w}), g[b].push_back({a, w});
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
vector<int> dis(n, INF);
q.push({0, s});
dis[s] = 0;
while (!q.empty()) {
auto [d, now] = q.top(); q.pop();
if (d > dis[now]) continue;
for (auto &[to_idx, to_dis] : g[now]) {
if (dis[now] + to_dis < dis[to_idx]) {
dis[to_idx] = dis[now] + to_dis;
q.push({dis[to_idx], to_idx});
}
}
}
if (dis[t] == INF) cout << "Case #" << c << ": " << "unreachable\n";
else cout << "Case #" << c << ": " << dis[t] << '\n';
}
}題目:UVA 1112
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
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
signed main() {
int N, I;
for (cin >> N; N--;) {
int n, e, t, m;
cin >> n >> e >> t >> m;
vector<vector<pair<int, int>>> g(n+1);
while (m--) {
int a, b, w;
cin >> a >> b >> w;
g[b].push_back({a, w});
}
vector<int> dis(n+1, INF);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, e});
dis[e] = 0;
while (pq.size()) {
auto [d, now] = pq.top(); pq.pop();
if (d > dis[now]) continue;
for (auto &[to_idx, to_dis] : g[now]) {
if (dis[now] + to_dis < dis[to_idx]) {
dis[to_idx] = dis[now] + to_dis;
pq.push({dis[to_idx], to_idx});
}
}
}
int ans = 0;
for (auto i : dis) if (i <= t) ans++;
cout << ans << '\n';
if (N) cout << '\n';
}
}