ALDS1_12_C 単一頂点最短距離 2
# 目次
# 問題
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_12_C
# 解説
隣接リストと優先度付きキューによるダイクストラ法
重み付き有向グラフのある頂点から各頂点への最短距離をもとめる.
各頂点は頂点<重み, ID>
というペアで表す.
priority_queue
のデフォルトの設定のままで重み順にソートさせるために、2つの工夫をしている.
- IDではなく重みをペアの第一要素にしている.
- デフォルトでは重みの大きい順にソートされてしまうので(最大ヒープ)、プッシュする際に重みに
-1
をかけて、ポップする時にもう一度-1
をかけてもとに戻すことで最小ヒープにしている.
こうしないと、priority_queue
に独自の比較オブジェクトを用意する必要がある.
グラフは、頂点数が多いので隣接行列ではなく隣接リストで表現する.
- 2つのコンテナと1つの優先度付きキューを宣言する
done[n]
各頂点の最短距離が確定したかいなか
dist[n]
各頂点の今考えれる最短距離(実行完了までは確定とは限らない)
priority_queue<Node> PQ
未確定でかつ原点からの距離が短い頂点順に並んだキュー
- コンテナを初期化する
done
全頂点false
dist
原点自身0
は距離0
を、その他は∞
PQ
原点0を距離0でプッシュする
- キューが空になるまで以下を繰り返す
- キューの先頭uを取得し、未確定であれば次に進む
- 確定済みにする
- すべての隣接頂点vについて以下を実行する
- vが未確定であれば次に進む
- 原点からuまでのコスト
dist[u]
とuからvへ距離weight(v)
の和が今の所考えられていた原点からvまでの最小距離dist[v]
よりも小さければ
- 最小距離を更新する
- キューにvのIDと原点からの最小距離をペアにしてプッシュする(この時距離をマイナスにするのを忘れずに)
- 原点からuまでのコスト
- distに原点0から各頂点への最短距離が確定されている
# 解答
#define MAX_N 10000
#define W_INF (1 << 21)
typedef pair<Int, Int> Node;
#define make_node(v,c) (make_pair(v,c))
#define weight(n) (n.first)
#define vertex(n) (n.second)
void sssp(vector<Node> nodes[], Int n, Int dist[]) {
bool done[n];
priority_queue<Node> PQ;
loop(i,0,n) done[i] = false, dist[i] = W_INF;
dist[0] = 0, PQ.push(make_node(0, 0));
while (!PQ.empty()) {
Node node = PQ.top(); PQ.pop();
Int u = vertex(node);
if (done[u]) continue;
done[u] = true;
for (auto n_v: nodes[u]) {
Int v = vertex(n_v);
if (done[v]) continue;
Int w = weight(n_v);
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
PQ.push(make_node(dist[v] * (-1), v));
}
}
}
}
int main(void) {
Int n, k, v, c;
cin >> n;
vector<Node> nodes[n];
Int dist[n];
loop(u,0,n) {
cin >> k >> k;
loop(i,0,k) {
cin >> v >> c;
nodes[u].push_back(make_node(c, v));
}
}
sssp(nodes, n, dist);
loop(i,0,n) cout << i << " " << dist[i] << endl;
}