0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

二重連結

Last updated at Posted at 2024-06-02

この記事のオリジナルは,2023年9月5日に公開されました.

概要

競技プログラミング用に,無向グラフの二重連結に関して,二重辺連結,橋,二重点連結,関節点,block cut tree などに関するライブラリを書きました.

概念

以下,グラフは単純とは限らない,無向グラフとします.

グラフのある辺を削除すると連結成分の数が増えるとき,その辺を (bridge) と呼ぶ.橋の無いグラフは,二重辺連結 (two-edge connected) であるという.グラフの点集合の部分集合が,二重辺連結部分グラフを導き,そのようなものの中で極大であるとき,これを二重辺連結成分と呼ぶ.

グラフのある点 (とその点が端点である辺) を削除すると,連結成分の数が増えるとき,その点を 関節点 (articulation point もしくは cutvertex) と呼ぶ.関節点の無いグラフで,大きさが3以上のものは,二重連結 ないし 二重点連結 (biconnected) であるという.グラフの点集合の部分集合が,(大きさが3以上とは限らない) 関節点の無いグラフを導き,そのようなものの中で極大であるとき,これを二重点連結成分ないしブロックと呼ぶ.

命題たち

以下のことがなりたつ.

  • 橋の端点は,葉であるときを除いて,関節点である.
  • 二重辺連結成分の全体は,グラフ点集合の分割になる.
  • 二重辺連結成分$A$, $B$ に,$(A, B) \in R \iff \exists a \in A \exists b \in B (a,b)$は橋.という関係を入れると,森になる.
  • 2つの二重点連結成分の共通部分は,空集合であるか,関節点1点からなる.

二重点連結成分全部の集合 $C$ と,関節点全部の集合 $A$ の和集合 $A \cup C$ に,$\{ \{a, c\} \mid a \in A, c \in C, a \in c \}$ で辺を入れたグラフは,森になります.元のグラフが連結ならば,木になります.これを,block cut tree__ (forest?) と言う.

ライブラリ

以下のような仕様のものを作りました.ソースはここにあります.自己ループや多重辺があっても,また,連結でなくても動作するはずです.

struct bridge {  // 二重辺連結に関する機能
  bridge(int size);  // constructor
  void add_edge(int u, int v);  // もとのグラフの辺の定義
  bool is_bridge(int u, int v); // 橋かどうか判定
  int num_tecc();               // 連結成分の数
  const vector<int>& tecc(int ccid);  // 各連結成分の頂点をあつめたvector
  int node_tecc_idx(int u);     // もとのグラフの点 u が属する連結成分の ID
  vector<pair<int, int>> tecc_edges();  // 上述の森の辺 (ペアの要素は,連結成分ID)
};

struct articulation {  // 二重点連結に関する機能
  articulation(int size);  // constructor
  void add_edge(int u, int v);  // もとのグラフの辺の定義
  bool is_articulation(int u);  // 関節点かどうか判定
  int bcc_size();               // 連結成分の数  (上と整合していないなあ...)
  const vector<int>& bcc(int idx);  // 各連結成分の頂点をあつめたvector
  enum kind { BLOCK, CUT };     // block-cut forest でどちらを表しているかを示す enum
  struct bctree {  // block-cut forest (名前が整合的でない...)
    int size();    // forest の頂点の数
    vector<pair<int, int>> edges();  // forest の辺
    pair<kind, int> what(int node);  // forest の頂点が,もとのグラフでは何か?
                  // {BLOCK, x} なら ID x である連結成分, {CUT, u} なら関節点 u
    int node(kind w, int i);  // what の逆.forest における頂点番号を返す.
  };
  bctree* make_bctree();   // Block Cut Forest を作る.戻り値はポインタであることに注意.
};

典型的な使用法は次のようになります.

二重辺連結

  int N; cin >> N;

  bridge bu(N);
  for (int i = 0; i < N; i++) {
    int u, v; cin >> u >> v; u--; v--;
    bu.add_edge(u, v);
  }
  int u = ..., v = ...;
  bu.is_bridge(u, v);  // (u, v) は橋か?
  for (int x = 0; x < bu.num_tecc(); x++) {
    for (int u : bu.tecc(x)) {
      ... u ... ;  // x 番目の二重辺連結成分 bu.tecc(x) の要素に順にアクセス
    }
  }
  int x = bu.node_tecc_idx[u];  // 頂点 u は x 番目の連結成分に属する
  for (auto [x, y] : bu.tecc_edges()) {
    // (x, y) が,上述の森の辺をなしている.
  }

なお,元のグラフが連結でない場合には,bu.tecc_edges() の関係は木にはならずに森になります.bu.llk.roots は,(型は vector<int> ),もとのグラフの連結成分から1点ずつとった集合になっています.

二重点連結

  int N; cin >> N;
  articulation au(N);
  for (int i = 0; i < N; i++) {
    int u, v; cin >> u >> v; u--; v--;
    au.add_edge(u, v);
  }
  int u = ...;
  au.is_articulation(u);  // u は関節点か?
  for (int x = 0; x < au.bcc_size(); x++) {
    for (int u : au.bcc(x)) {
      ... u ...;  // x 番目の二重点連結成分 au.bcc(x) の要素に順にアクセス
    }
  }

  // Block-Cut tree に,別のライブラリである Tree を使う場合
  // この下は,元のグラフが連結であるという前提のコードになっている...
  //    (ライブラリ自体は,そうでなくても動作はする.bctree() という名前になっているが....)
  auto bctree = au.make_bctree();
  ll sz = bctree->size();  // Block-Cut tree の頂点数
  Tree bct(0, sz);
  for (auto [a, b] : bctree->edges()) bct.add_edge(a, b);
     // bctree->edges() が,Block Cut tree としての辺の関係
  for (int a = 0; a < sz; a++) {
    auto [w, i] = bctree->what(a);  // aは BLOCK? それとも CUT?
    if (w == articulation::BLOCK) {
      // この連結成分は,au.bcc(i) である.
    }else if (w == articulation::CUT) {
      // この関節点は,(もとのグラフの頂点番号で) i である.
    }else assert(0);
    // what の逆変換が bctree->node() である.
  }
  

実装は,lowlink を使っています.DFS 木の行きがけ順を表す vector<int> _ord と,back edge を高々1回たどって到達できる点の _ord の値の最小値である vector<int> _low を最初に計算し,これらを用いて橋や関節点の判定をしています.

参考サイト

けむさんの 「二重連結性と lowlink の話」 がたいへん参考になりました.お礼申し上げます.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?