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

Preview:

Citation preview

競技プログラミング練習会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 310 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 310 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 310 20

60

15

30

グラフの実装

●隣接グラフ●各頂点から伸びる辺のリスト

●無向グラフのときは互いに逆向きの辺が2本あると考える

●頂点数が多くても大丈夫

●多重辺があっても大丈夫

0 (1,10),(2,15)

1 (0,20),(2,60)

2 (3,30)

3 -

1

0

2 310 20

60

15

30

最短経路問題

最短経路問題

●頂点間の距離を求める問題●全点対最短経路問題…全ての頂点間の距離

●単一始点最短経路問題…ある点から各点への距離

1

0

23

1020

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

23

1020

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

23

1020

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

23

1020

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 < d

0 + 10 = ∞+10

(更新しない)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 = ∞ < d

0 + 10 = ∞+15

(更新しない)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 = ∞ > d

1 + 20 = 20

(更新する)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 = ∞ > d

1 + 60 = 60

(更新する)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 = ∞ > d

2 + 30 = 90

(更新する)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 < d

0 + 10 = 30

(更新しない)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 > d

0 + 15 = 35

(更新する)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 = d

1 + 20 = 20

(更新しない)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 < d

1 + 60 = 60

(更新しない)

ベルマンフォード法の動作

●各辺に対してd終点 > d始点+コストでないか調べる

1

0

23

1020

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 > d

2 + 30 = 65

(更新する)

ベルマンフォード法の動作

●辺のリストを1周したとき、距離を1回も更新できなければもう距離を更新できないので終了する

●このときのdiが最短距離1

0

23

1020

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)

Recommended