Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【2019-06-19】アルゴリズム勉強会 - 最小全域木

【2019-06-19】アルゴリズム勉強会 - 最小全域木

Hidehisa Arai

June 19, 2021
Tweet

More Decks by Hidehisa Arai

Other Decks in Technology

Transcript



  1. 2021/06/19

    アルゴリズム勉強会

    Hidehisa Arai

    1

    View Slide

  2. はじめに

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    => 最小全域木

    2

    View Slide

  3. ナイーブな考え方①

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    =>コストが小さい辺からとりあえず採用してみよう 

    途中経過

    3

    View Slide

  4. ナイーブな考え方②

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    =>コストが小さい辺からとりあえず採用してみよう 

    途中経過

    次にコストの低い辺は
    これだが、採用すると
    巡回が発生する・・・

    =>巡回が発生しそうならスキップ! 
 4

    View Slide

  5. ナイーブな考え方③

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    =>コストが小さい辺からとりあえず採用してみよう 

    いつ終わるの?

    => 全ノードを繋いだら終わり! 

    5

    View Slide

  6. ナイーブな考え方 - アルゴリズムを書き下してみる

    ● 入力の辺のコストが小さい順に採用していく

    ○ コスト順にソートしておくと良さそう! 

    ● 巡回が発生しそうだったらスキップする

    ○ 巡回が発生しそうってなに? 

    ● 全ノードを繋いだら終わり!

    ○ 簡単に判別する方法はある? 

    ○ => 最終的には「木」になるのでノード数 - 1個の辺を採用
    したら終わり!

    水源 a
    b
    c
    e
    h
    10
    15
    18
    33
    11
    21
    20
    6
    繋いでは
    ダメな辺

    繋いでもOK
    な辺
 6

    View Slide

  7. ナイーブな考え方 - 巡回が発生しそうってなに?

    水源 a
    b
    c
    e
    h
    10
    15
    18
    33
    11
    21
    20
    6
    同じ部分グラフ=
    連結成分

    別の部分グラフ=連
    結成分でない

    両ノードが連結成分なエッジを選ば
    ないようにしたい

    =>連結成分の判定って? 

    =>Union Find!

    7

    View Slide

  8. ナイーブな考え方 - アルゴリズムを書き下してみる

    ● 入力の辺のコストが小さい順に採用していく

    ○ コスト順にソートしておくと良さそう! 

    ● 巡回が発生しそうだったらスキップする

    ○ 両ノードが連結成分なエッジをスキップする 

    ○ => Union Findで連結かどうか判定 

    ● 全ノードを繋いだら終わり!

    ○ 簡単に判別する方法はある? 

    ○ => 最終的には「木」になるのでノード数 - 1個の辺を採
    用したら終わり!

    あり本間違えてる・・・? 

    クラスカル(Kruskal)法といいます 

    8

    View Slide

  9. クラスカル法 - 計算量

    O(ElogE)

    O(V)

    O(Vα(n))

    ※α(n)はアッカーマン関数の逆関数 

    O(ElogE)

    O(ElogV)

    OR†

    † E < V2 なためlogE < logV2 = 2logV
    9

    View Slide

  10. 別の考え方①

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    => 連結を保ちながらちょっとずつ木を大きくすることもできるのでは? 

    最初は重み最小の辺で良さそう、次は? 

    10

    View Slide

  11. 別の考え方②

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    => 連結を保ちながらちょっとずつ木を大きくすることもできるのでは? 

    最初は重み最小の辺で良さそう、次は? 

    => すでに連結されている成分で最小コストの辺を繋ぐ 

    次にコストの低い辺は
    これだが、採用すると
    巡回が発生する・・・

    =>巡回が発生しそうならスキップ! 
 11

    View Slide

  12. 別の考え方③

    水源 a
    b
    d
    f
    c
    e
    h
    i
    k
    l
    j
    g
    10
    15
    18
    33
    11
    21
    20
    6
    85
    9
    56
    2
    22
    77
    5
    39
    30
    81
    14
    12
    38
    41
    67
    水源から村の各戸に水道を引きたい。コスト最小になる引き方は? 

    => 連結を保ちながらちょっとずつ木を大きくすることもできるのでは? 

    いつ終わるの?

    => 全てのノードが繋がれば終わり! 

    12

    View Slide

  13. 別の考え方 - アルゴリズムを書き下してみる

    ● 初めはコスト最小の辺を選ぶ(必須ではない)

    ● すでに連結な成分に繋がっている辺の中で最小
    コストの辺を選ぶ、ただし巡回が発生しそうな時は
    スキップ

    ○ 連結成分から伸びる辺で最小コストの辺ってどうやって
    見つける?

    ○ 巡回が発生しそうってなに? 

    ● 全ノードを繋いだら終わり!

    ○ 簡単に判別する方法はある? 

    ○ => 最終的には「木」になるのでノード数 - 1個の辺を採用
    したら終わり!

    d
    f
    h
    i
    k
    j
    g
    9
    2
    22 5
    81
    41 最小がこれな
    ことをどう判定
    する?

    13

    View Slide

  14. 別の考え方 - 最小コストの辺をどう見つける?

    d
    f
    h
    i
    k
    j
    g
    9
    2
    22 5
    81
    12
    41
    minCost[h] = 22
    minCost[k] = 5
    minCost[j] = 81
    minCost[g] = 41
    minCost[d] = 9
    連結成分からそれ
    以外のノードへの
    最小移動コストを計
    算しておき、その中
    で最小の値をとる。

    d
    f
    e
    h
    i
    k
    j
    g
    9
    2
    22 5
    81
    41
    67
    minCost[e] = INF
    連結成分から
    いけないノー
    ドはINF
    e
    67
    minCost[h] = 22
    minCost[k] = 5
    used[k] = true
    minCost[j] = 81
    minCost[d] = 9
    minCost[e] = INF
    minCost[g] = min(41, 12)
    14

    View Slide

  15. ● すでに連結な成分に繋がっている辺の中で最小コストの辺を選ぶ、ただし巡回が
    発生しそうな時はスキップ

    ○ 連結成分から伸びる辺で最小コストの辺ってどうやって見つける? 

    ■ 連結成分からのそれ以外のノードへの最小コストを保持しておく 

    ■ 連結成分から直接いけないノードへの最小コストはINF 

    ■ 辺を選択した後、最小コストを更新する必要がある 

    ● 全てのノードについて新しく追加されたノードからのコストと現在のminCostを比較する 

    ○ 巡回が発生しそうってなに? 

    ■ クラスカル法と違い、同じ連結成分かどうか調べる必要はない(連結成分は必ず一つの木) 

    ■ すでに連結成分になったかどうかを記録しておくだけでヨシ! 

    ■ 次の最小の辺は「まだ連結されていない辺」から選ぶ 

    別の考え方 - 最小コストの辺をどう見つける?

    15

    View Slide

  16. 別の考え方 - 必要な要素を考える
    連結成分からのそれ以外のノードへの最小コストを保持しておく連結
    成分から直接いけないノードへの最小コストはINF 

    => minCostの配列が必要。|minCost| = VでINFで初期化する。 

    すでに連結成分になったかどうかを記録しておくだけでヨシ!
    => 連結成分かどうかの配列が必要。|used| = Vでfalseで初期化する。 

    次の最小の辺は「まだ連結されていない辺」から選ぶ
    => 全てのノードvについてused[v] = falseかつminCost[v]が最小かを確認 

    全てのノードについて新しく追加されたノードからのコストと現在のminCostを比較する 

    => ノードからノードへのコストを保持する行列Costが必要。辺が実際には存在し
    ないところはINFで初期化する。 

    => 全てのノードvについて現在のminCost[v]とCost[v][u]の比較をし、Cost[v][u]
    の方が小さければminCost[v] = Cost[v][u]となる。 
 16

    View Slide

  17. 別の考え方 - アルゴリズム全体

    ノードからノードへのコストを保持する行列が必
    要。辺が実際には存在しないところはINFで初期
    化する。
    minCostの配列が必要。|minCost| = VでINFで初
    期化する。
    連結成分かどうかの配列が必要。|used| = Vで
    falseで初期化する。
    全てのノードvについてused[v] = falseかつ
    minCost[v]が最小かを確認
    全てのノードvについて現在のminCost[v]と
    Cost[v][u]の比較をし、Cost[v][u]の方が小さけ
    ればminCost[v] = Cost[v][u]となる。
    17
    プリム(Prim)法といいます 


    View Slide

  18. 別の考え方 - 計算量

    O(V)

    V回実行される

    単体でO(V)

    単体でO(V)

    O(V2)

    O(V2)

    V×

    V×

    O(V2)

    18

    View Slide

  19. 別の考え方 - 計算量改善

    プライオリティキューを使う => O(logV)

    隣接リストを使う

    O((V+E)logV)

    19

    View Slide