Official

E - Wi-Fiアクセスポイントの設置 / Installation of Wi-Fi Access Points Editorial by kyopro_friends


この問題は最大流を用いて解くことができます。

建物を頂点、通路を辺とした二部グラフを考えることで、この問題は最小頂点被覆問題そのものになります。

二部グラフの最小頂点被覆の大きさは、最大マッチングの大きさと一致することが知られています(ケーニヒの定理(König’s theorem))。

二部グラフの最大マッチングは、ソースとシンクを適切に補ったネットワークにおける最大流と一致するため、 \(O(\sqrt{N}M)\)でこの問題を解くことができます。

実装例 (C++)

#include<bits/stdc++.h>
#include<atcoder/maxflow>
using namespace std;

int main(){
  int n, m;
  cin >> n >> m;
  vector<vector<int>> G(n);
  for(int i=0; i<m; i++){
    int u, v;
    cin >> u >> v;
    u--, v--;
    G[u].push_back(v);
    G[v].push_back(u);
  }

  vector<int>color(n, -1);
  for(int i=0; i<n; i++){
    if(color[i] == -1){
      queue<int>q({i});
      color[i] = 0;
      while(q.size() > 0){
        int v = q.front(); q.pop();
        for(int vv: G[v]){
          if(color[vv] == -1){
            color[vv] = color[v] ^ 1;
            q.push(vv);
          }
        }
      }
    }
  }

  atcoder::mf_graph<int> g(n+2);  // n: source, n+1: sink
  for(int v=0; v<n; v++){
    if(color[v] == 0){
      g.add_edge(n, v, 1);
      for(int vv: G[v]){
        if(color[vv] == 1){
          g.add_edge(v, vv, 1);
        }
      }
    }else{
      g.add_edge(v, n+1, 1);
    }
  }
  cout << g.flow(n, n+1) << endl;
}

実装例 (Python)

ACLを使う場合、実行時間制限が非常にタイトです。

from atcoder.maxflow import MFGraph

N, M = map(int, input().split())
G = [[] for _ in range(N)]
for _ in range(M):
  u, v = map(int, input().split())
  u -= 1
  v -= 1
  G[u].append(v)
  G[v].append(u)

color = [-1] * N
for i in range(N):
  if color[i] == -1:
    stack = [i]
    color[i] = 0
    while len(stack) > 0:
      v = stack.pop()
      for vv in G[v]:
        if color[vv] == -1:
          color[vv] = color[v] ^ 1
          stack.append(vv)

g = MFGraph(N+2)  # n: source, n+1: sink
for v in range(N):
  if color[v] == 0:
    g.add_edge(N, v, 1)
    for vv in G[v]:
      if color[vv] == 1:
        g.add_edge(v, vv, 1)
  else:
    g.add_edge(v, N+1, 1)

print(g.flow(N, N+1))

おまけ:ケーニヒの定理の略証

最大マッチングのサイズを \(m\) 、最小頂点被覆のサイズを \(c\) とする。

\(m \leq c\) であること

最大マッチング \(M\) と最小頂点被覆 \(C\) を任意の取る。\(C\) は頂点被覆なので、\(M\) に属する各辺の両端の少なくとも一方は \(C\) に属する。そこで、\(M\) に属する辺 \(e\) に対し、\(e\) の端点かつ \(C\) に属する頂点を対応させる写像 \(f:M\to C\) を考える。\(M\) はマッチングなので頂点を共有しておらず、\(f\) は単射になる。よって \(m \leq c\) である。

\( m\geq c\) であること

サイズ \(m\) の頂点被覆を構築する。与えられた二部グラフ \(G\) の部集合を \(A,B\) とし、次のようなネットワークグラフ \(G'\) を考える。

  • 頂点集合は \(A\cup B \cup\{s,t\}\)
  • \(G\) の各辺 \(e=(u,v)\) に対し、容量 \(\infty\) の辺 \((u,v)\) を張る
  • \(A\) の各頂点 \(a\) に対し、容量 \(1\) の辺 \((s,a)\) を張る
  • \(B\) の各頂点 \(b\) に対し、容量 \(1\) の辺 \((b,t)\) を張る

\(G\) の最大マッチングの大きさ \(m\)\(G'\) の s-t 最大流のサイズに等しい。また、最大フロー最小カット定理より、\(G'\) の s-t 最大流のサイズは \(G'\) の s-t 最小カットのサイズに等しい。

\(G'\) の s-t 最小カットを \((S,T)\) とし、\(A_S=A\cap S\) と定める。同様に \(A_T,B_S,B_T\) を定める。 \(G\) の辺容量は \(\infty\) であるから、最小カットは \(G\) の辺を含まず、 \(A_S\)\(B_T\) の間に辺はない。よって s-t 最小カットのサイズは \(|A_T|+|B_S|\) となる。一方、\(A_S\)\(B_T\) 間に辺はないことから、\(G\) の辺は全て \(A_T \cup B_S\) を端点に持ち、これは \(G\) の頂点被覆である。よって \(m=|A_T|+|B_S|=|A_T\cup B_S|\geq c\) である。

参考:wikipedia

posted:
last update: