2020年12月26日土曜日

CodeChef - Two Closest

問題: 無向グラフG=(V,E)G=(V, E)VVの部分集合SS (special node)が与えられる。SS上の任意の2点間の距離で最短のものを求めよ。

方針: すべてのspecial nodeから各点への最短距離を調べるためにKK回ダイクストラする。この際、距離のテーブルは毎回使いまわしてよくて、枝刈りができる。また、special nodeを調べる順番をシャッフルすれば期待計算量が保証できる。

正当性について。今、special node A1,...,Ai1A_1, ..., A_{i-1}について二頂点間の最短距離の最小値が求まっているとし、距離のテーブルddd[v]:=vd[v] := vA1,...,Ai1A_1, ..., A_{i-1}との最短距離の最小値、という状態になっているとする。ここからさらにspecial node AiA_iを始点にダイクストラするとする。この際、頂点uuからvvを更新しようとした時にd[u]+w(u,v)d[v]d[u] + w(u, v) \ge d[v]であれば、vvは無視してよい。なぜならAiA_iから任意の頂点xxに到達する際の最短経路がvvを通るとしても、それ以下の距離でA1,...,Ai1A_1, ..., A_{i-1}のいずれかからxxに到達できることになるからだ。

計算量について。KK回ダイクストラをしている間に頂点vvがキューからポップされる回数の期待値を考える。vvがキューからポップされるのは、今調べているspecial nodeとvvの最短距離が以前調べたすべてのspecial nodeとvvの最短距離より小さい場合である。したがって、この期待値はKK個のspecial nodeとvvとの最短距離をd1,...,dKd_1, ..., d_Kとした時、(di)(d_i)をシャッフルした列のLDSの長さの期待値に等しく、O(K){O}(\sqrt K)らしい[1]。したがって、ポップに関する期待計算量はO(KNlogN){O}(\sqrt KN \log N)となる。また、ポップした頂点の隣接頂点を調べてdecrease keyする操作の期待計算量は、二分ヒープならO(KMlogN){O}(\sqrt KM \log N)となる。 したがって、全体の期待計算量はO(K(M+N)logN){O}(\sqrt K (M+N)\log N)ということになる。

waterfallsさんの別の乱択の方針も面白かった。special nodeをランダムに2分割して、一方を始点としたダイクストラをすると、最短距離を与える二頂点が異なるグループに属している時に正しい答えが出る。そうなる確率は1/2なので、何回もやって最小値を取ればよい。このテクニックは無向グラフの最短閉路アルゴリズムで見たことがある: http://research.haifa.ac.il/~raphy/papers/all-cycles.pdf


  1. この評価については https://www.math.ucdavis.edu/~romik/book/ のp.9に簡潔な証明が載っている。ランダム順列のLISの長さの期待値に関する研究はJ. M. Hammersley, A few seedlings of researchが初出らしい。(後者は読んでいない) ↩︎