Official

F - Zebraness Editorial by tatyam


この問題は、それぞれの ?B または W を割り当てて、

  • \(c_{1,1}\)B\(c_{1,2}\)W なら \(1\) 点得る
  • \(c_{1,1}\)W\(c_{1,2}\)B なら \(1\) 点得る
  • \(c_{1,1}\)B\(c_{2,1}\)W なら \(1\) 点得る
  • \(c_{1,1}\)W\(c_{2,1}\)B なら \(1\) 点得る
  • \(c_{1,2}\)B\(c_{1,3}\)W なら \(1\) 点得る
    \(\quad\vdots\)

といった条件の元で点数を最大化する問題と言うことができます。
このような形の問題はあるグラフの最小カットに帰着して解くことがあります。

関連資料 : https://www.slideshare.net/shindannin/project-selection-problem
(燃やす埋める問題, Project Selection Problem で調べてみましょう)

まず、 \(2N(N-1)\) 点先に得られるとして、「\(1\) 点得る」を「\(1\) 点失う」に変換します。

  • \(c_{1,1}\)B\(c_{1,2}\)B なら \(1\) 点失う
  • \(c_{1,1}\)W\(c_{1,2}\)W なら \(1\) 点失う
  • \(c_{1,1}\)B\(c_{2,1}\)B なら \(1\) 点失う
  • \(c_{1,1}\)W\(c_{2,1}\)W なら \(1\) 点失う
  • \(c_{1,2}\)B\(c_{1,3}\)B なら \(1\) 点失う
    \(\quad\vdots\)

しかし、この形では最小カットに帰着することができないので、グリッドが \(2\) 部グラフであることに注目し、\(i + j\) が奇数であるような \(c_{i,j}\) について、BW を反転します。

  • \(c_{1,1}\)B\(c_{1,2}\)W なら \(1\) 点失う
  • \(c_{1,1}\)W\(c_{1,2}\)B なら \(1\) 点失う
  • \(c_{1,1}\)B\(c_{2,1}\)W なら \(1\) 点失う
  • \(c_{1,1}\)W\(c_{2,1}\)B なら \(1\) 点失う
  • \(c_{1,2}\)W\(c_{1,3}\)B なら \(1\) 点失う
    \(\quad\vdots\)

入力で BW が指定されている場合、非常に大きな定数 \(INF\) を用いて

  • \(c_{i, j}\)B なら \(INF\) 点失う

などと条件を追加すれば ? であるものとして扱えます。

これで最小カットに帰着することができます。具体的には以下のようにすると良いです。

  • 頂点 \((i, j)\) から頂点 \((i, j + 1)\) に容量 \(1\) の辺を張る
  • 頂点 \((i, j)\) から頂点 \((i + 1, j)\) に容量 \(1\) の辺を張る
  • 頂点 \((i, j)\) から頂点 \((i, j - 1)\) に容量 \(1\) の辺を張る
  • 頂点 \((i, j)\) から頂点 \((i - 1, j)\) に容量 \(1\) の辺を張る
  • BW の反転を行った後 \(c_{i,j}\)B であれば、頂点 \(S\) から頂点 \((i, j)\) に容量 \(INF\) の辺を張る
  • BW の反転を行った後 \(c_{i,j}\)W であれば、頂点 \((i, j)\) から頂点 \(T\) に容量 \(INF\) の辺を張る
  • \(S\) から \(T\) への最小カットの容量を求める。これは、\(S\) から \(T\) への最大フローの流量と等しい。

計算量は、 Dinic 法を用いれば \(O(N^3)\) です。
実装には AC Librarymaxflow を利用できます。

回答例 (C++)

回答例 (Python)

posted:
last update: