G - ダンジョン2 Editorial by keisuke6

L<=12 解

1. 前計算と辺の発見

まず前計算として、初期頂点を根とする DFS 木を構成する。このとき Move をちょうど \(2M\) 回行えばよい(各辺を往復ちょうど 1 回ずつ通るため)。

各頂点の状態を次の 3 色で管理する:

  • 色 1:未訪問
  • 色 2:訪問済みであり、その部分木を現在探索中
  • 色 3:訪問済みであり、その部分木の探索が終了

頂点番号は DFS の行きがけ順で適当に付与しておく。

現在頂点 \(u\) にいるとき、隣接頂点 \(v\) が色 2 であれば、DFS 木上で \(v\)\(u\) の祖先である。

このとき、辺 \(e = (u,v)\) を使って Move し、移動先の色が 2 だった場合、辺 \(e\) が「発見された」と定義する。

ここで、DFS 木に含まれない任意の辺は、探索中にちょうど 1 回だけ発見される。

理由は次の通り:

  • 任意の辺 \(u-v\) の端点は DFS 木上で必ず祖先・子孫関係にある
  • 深い方の頂点を探索している時に、その祖先との辺がちょうど 1 回だけ観測される

したがって、各非木辺は一意に特定される。


2. もう一方の端点の特定方法

\(e\) が発見されたとき、そのとき探索中だった頂点が片方の端点である。

したがって、もう一方の端点が「どの祖先か」を特定できればよい。

次の DFS を用いることで、「もう一方の端点の \(X\) 進数表記における第 \(k\) 桁」をすべての辺について特定できる。

アルゴリズム

  1. DFS 木を行きがけ順に走査する。現在頂点を \(u\) とする。
  2. \(u\) から子へ移動する直前に、\(u\) の色を「\(u\)\(X\) 進数表記の \(k\) 桁目」に対応する色に設定する。
  3. \(u\) を端点に持つと既に分かっている辺 \(e\) について、その辺を使った先の色を確認する。その色が「もう一方の端点の第 \(k\) 桁」の値である。

この DFS では、各辺はちょうど 2 回通られる。


3. 全端点の特定と計算量

色は 3 種類使えるため、\(3^5 = 243 \ge 200\) より、5 桁あれば最大 200 頂点を識別できる。

したがって、この DFS を 5 回(各桁について 1 回ずつ)実行すれば、すべての辺の両端点を特定できる。

Move 回数は、前計算の DFS に \(2M\) 回、各桁ごとの DFS にそれぞれ \(2M\) 回かかるため、\(2M \times (1 + 5) = 12M\) 回の Move で完了する。

AC コード (C++) : https://atcoder.jp/contests/joisc2016/submissions/73234551

posted:
last update: