Dijkstra法(ダイクストラ法)
- 重み付きグラフの最短経路を求めるアルゴリズム。
- 始点からの最短距離を求める。
- 辺の重みが負でない場合に使える。
- 今回は優先度付きキューを使って実装する。
- 同じく最短経路を考えるBFSは重みの無い(もしくは重みの等しい)グラフにしか用いることができなかったが、Dijkstra法は重みが辺ごとに違うグラフにも対応できる。
優先度付きキュー
- 優先度付きキューは、入れた順番ではなく、優先度の高い順に取り出すデータ構造。
- C++では
priority_queue
を使う。
priority_queue
はデフォルトで降順になるので、昇順にする場合はgreater
を使う。
priority_queue<int> q;
priority_queue<int,vector<int>,greater<int>> q;
q.top();
q.pop();
q.push(1);
実装テンプレート
#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
ll n, m;
cin >> n >> m;
vector<vector<pair<ll, ll>>> g(n);
rep(i, m) {
ll a, b, c;
cin >> a >> b >> c;
a--, b--;
g[a].push_back({b, c});
g[b].push_back({a, c});
}
vector<ll> dist(n, 1e18);
dist[0] = 0;
priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
q.push({0, 0});
while (!q.empty()) {
auto [d, v] = q.top();
q.pop();
if (dist[v] < d) continue;
for (auto [nv, nd] : g[v]) {
if (dist[nv] > dist[v] + nd) {
dist[nv] = dist[v] + nd;
q.push({dist[nv], nv});
}
}
}
cout << dist[n - 1] << endl;
}
- この記事にもDijkstra法の解説があります。一つ一つの処理を理解するのに役立ちます。
例題
ヒント
- テンプレを書き換えると解けます。
- 始点に注意して、どう動いているのか確認しながら解いてみてください。
解答例
#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
ll n, m, r;
cin >> n >> m >> r;
vector<vector<pair<ll, ll>>> g(n);
rep(i, m) {
ll a, b, c;
cin >> a >> b >> c;
g[a].push_back({b, c});
}
vector<ll> dist(n, 1e18);
dist[r] = 0;
priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
q.push({0, r});
while (!q.empty()) {
auto [d, v] = q.top();
q.pop();
if (dist[v] < d) continue;
for (auto [nv, nd] : g[v]) {
if (dist[nv] > dist[v] + nd) {
dist[nv] = dist[v] + nd;
q.push({dist[nv], nv});
}
}
}
rep(i, n) {
if (dist[i] < 1e18)
cout << dist[i] << endl;
else
cout << "INF" << endl;
}
}
演習問題