競技プログラミング練習会
2015 Normal
第3回
2015/05/01
長嶺英朗(ID:hnagamin)
目次
●
グラフ
– グラフとは
– グラフに関する用語
●
最短経路問題
●
ベルマンフォード法
●
ワーシャルフロイド法
グラフ
この辺りのページの多くは、
http://www.slideshare.net/KMC_JP/graph-and-tree
から引用しています
グラフ
●頂点と辺の集合
●辺は頂点と頂点を結ぶ
●辺に向きがあるものを有向グラフ、向きのないもの
を無向グラフという
頂点
辺
無向グラフ
グラフ
●頂点と辺の集合
●辺は頂点と頂点を結ぶ
●辺に向きがあるものを有向グラフ、向きのないもの
を無向グラフという
頂点
辺
有向グラフ
グラフに関する用語
●道(パス):一続きの頂点の列
グラフに関する用語
●閉路(サイクル):始点と終点が同じパス
グラフに関する用語
●距離:2頂点を結ぶ最短の道の長さ
距離: 2
グラフに関する用語
●直径:距離の最大値
直径: 2
グラフに関する用語
●ループ:辺の両端が同じ頂点になっているもの
グラフに関する用語
●多重辺:辺の両端の組が等しい複数の辺
グラフに関する用語
●単純グラフ:ループも多重辺も無いグラフ
単純グラフでない
グラフに関する用語
●単純グラフ:ループも多重辺も無いグラフ
単純グラフである
グラフに関する用語
●連結グラフ:どの2点間にも道があるグラフ
連結でない
グラフに関する用語
●連結グラフ:どの2点間にも道があるグラフ
連結である
グラフに関する用語
●次数:頂点に接続している辺の本数
3
4
5
4
5
3
グラフに関する用語
●正則グラフ:全頂点の次数が等しいグラフ
4
4
4
4
4
4
グラフに関する用語
●完全グラフ:どの2点間にも辺があるグラフ
グラフの実装
●隣接行列
●グラフを2次元配列で表す
●iからjにコストwの辺があるとき
a[i][j]=wとする
●実装が楽
●頂点数が多くなるとメモリを浪費
する
●多重辺への対応が難しい
0 1 2 3
0 0 10 15 0
1 20 0 60 0
2 0 0 0 30
3 0 0 0 0
1
0
2 3
10 20
60
15
30
グラフの実装
●隣接行列
●グラフを2次元配列で表す
●iからjにコストwの辺があるとき
a[i][j]=wとする
●実装が楽
●頂点数が多くなるとメモリを浪費
する
●多重辺への対応が難しい
0 1 2 3
0 -1 10 15 -1
1 20 -1 60 -1
2 -1 -1 -1 30
3 -1 -1 -1 -1
1
0
2 3
10 20
60
15
30
グラフの実装
●隣接行列
●グラフを2次元配列で表す
●iからjにコストwの辺があるとき
a[i][j]=wとする
●実装が楽
●頂点数が多くなるとメモリを浪費
する
●多重辺への対応が難しい
0 1 2 3
0 ∞ 10 15 ∞
1 20 ∞ 60 ∞
2 ∞ ∞ ∞ 30
3 ∞ ∞ ∞ ∞
1
0
2 3
10 20
60
15
30
グラフの実装
●隣接グラフ
●各頂点から伸びる辺のリスト
●無向グラフのときは互いに逆向き
の辺が2本あると考える
●頂点数が多くても大丈夫
●多重辺があっても大丈夫
0 (1,10),(2,15)
1 (0,20),(2,60)
2 (3,30)
3 -
1
0
2 3
10 20
60
15
30
最短経路問題
最短経路問題
●頂点間の距離を求める問題
●全点対最短経路問題…全ての頂点間の距離
●単一始点最短経路問題…ある点から各点への距離
1
0
2
3
10
20
60
15
30
頂点1 0: 20⇒
頂点1 1: 0⇒
頂点1 2: 35⇒
頂点1 3: 65⇒
単一始点最短経路問題の例
ベルマンフォード法
●単一始点最短経路問題を解く
●計算量O(VE)
●V: 頂点数, E: 辺の数
ベルマンフォード法のアイデア
●各頂点への暫定的な最短経路を保存しておく
●各辺を使うことで最短経路を更新できるか調べる
●コストwの辺i→jについて、dj > di + w か調べる
●diは始点からiへの距離
ベルマンフォード法の動作
●始点を除く各頂点に対してdi = ∞とする
●実際には(とても大きい)有限の数にする
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di ∞ 0 ∞ ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di ∞ 0 ∞ ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di ∞ 0 ∞ ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d1
= 0 < d0
+ 10 = ∞+10
(更新しない)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di ∞ 0 ∞ ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d2
= ∞ < d0
+ 10 = ∞+15
(更新しない)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 ∞ ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d0
= ∞ > d1
+ 20 = 20
(更新する)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 60 ∞
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d2
= ∞ > d1
+ 60 = 60
(更新する)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 60 90
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d3
= ∞ > d2
+ 30 = 90
(更新する)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 60 90
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d1
= 0 < d0
+ 10 = 30
(更新しない)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 35 90
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d2
= 60 > d0
+ 15 = 35
(更新する)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 35 90
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d0
= 20 = d1
+ 20 = 20
(更新しない)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 35 90
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d2
= 35 < d1
+ 60 = 60
(更新しない)
ベルマンフォード法の動作
●各辺に対してd終点 > d始点+コストでないか調べる
1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 35 65
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
d3
= 90 > d2
+ 30 = 65
(更新する)
ベルマンフォード法の動作
●辺のリストを1周したとき、距離を1回も更新できな
ければもう距離を更新できないので終了する
●このときのdiが最短距離 1
0
2
3
10
20
60
15
30
頂点i 0 1 2 3
距離di 20 0 35 65
辺のリスト
(0,1,10), (0,2,15), (1,0, 20), (1,2,60), (2,3,30)
ベルマンフォード法の計算量
●負の閉路がないとき
●最初は始点から始点への距離(0)が確定している
●辺のリストを1周すると、距離が確定した頂点に隣接
するもののうち少なくとも1つの距離が確定する
●この頂点の距離は今後2度と更新されない
●従って、(V-1)周すると全ての頂点の距離が定まる
●O((V-1)E) = O(VE)
ベルマンフォード法の計算量
●負の閉路があるとき
●一部の頂点について“最短距離”が定まらない
●辺のリストをV周しても、負の閉路を構成する頂点
の最短距離は更新される
●V周目でも更新されると負の閉路があることが分
かるので、そこで計算を打ち切る
●O(VE)で負の閉路の検出ができる
ワーシャルフロイド法
●全点対最短経路問題を解く
●計算量O(V3)
●V: 頂点数
●実装が簡単
●頂点数が小さい場合には単一始点最短経路問題
でもこれを使うことがある
ワーシャルフロイド法のアイデア
●dij > dik + dkj なら、iからkを経由してjに行くことで
iからjへより小さいコストで行くことができる
●全ての(i, j, k)についてこれを調べる
k
ji dij
dik dkj
ワーシャルフロイド法の実装
●隣接行列を持っておくと良い
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
d[i][j] = (i == j ? 0 : INFINITY);
}
}
for (int i = 0; i < E; i++) {
d[edges[i].from][edges[i].to] = edges[i].cost;
}
for (int k = 0; i < V; i++) {
for (int i = 0; j < V; j++) {
for (int j = 0; k < V; k++) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
行列の初期化
最短距離の更新
ワーシャルフロイド法の計算量
●プログラムの形式から明らかにO(V3)

競技プログラミング練習会2015 Normal 第3回