ネットワークフロー
最近フロー関連をやってたのでそのメモ
最大流
頂点辺の有向グラフ 各辺には容量が定義されている
をそれぞれ頂点から出る/入る辺の集合とする
始点を,終点をとする
LPの形で書くと以下の通り
ford-fulkerson
最大流を求めるアルゴリズムの一つ 最大流の流量をとして
用語定義
- 残余グラフ: である辺および,である辺の逆辺から成るグラフ
- 増加パス: 残余グラフ上のs-tパス
増加パスが存在したらそのパスに沿って目一杯フローを流す.この処理を増加パスが存在しなくなるまで繰り返す.
最大フロー最小カット定理
最大のs-tフロー = 最小のs-tカット
ford-fulkerson,最大フロー最小カット定理の証明は蟻本p191
ford-fulkersonで最大流が求まることから,存在性・容量が整数であればフローも整数であることがわかる
増加パスが存在しない 残余グラフに対応するフローが最大流 からも証明できる
最大フロー最小カット定理はLPの双対定理からも確認できる
- LPとグラフと定式化 by とこはるさん の2.2節
- ネットワークフロー入門 by hosさん のⅢ
最小カットの復元
最大フローに対応する残余グラフにはs-tパスが存在しない.残余グラフで始点 から到達できる頂点の集合を ,到達できない頂点の集合を とするとカット は最小カットである.
Dinic
最大流を求めるアルゴリズムの一つ 最悪だが多くのケースで高速に動作する
参考資料
- 最大流問題について. by Mi_Sawaさん
- 蟻本p194
Dinic法の正当性は 増加パスが存在しない 残余グラフに対応するフローが最大流 から証明できる
特殊なグラフなら高速に動作する保証つき
- 二部マッチング →
Hopcroft-karpはDinicで最大流を流すのと同じ(だったはず)
二部マッチングでTLEに苦しんだ話 by snukeさん 高速な二部マッチング
頂点辺の二部グラフの最大マッチングが225ms 提出 - 辺の重みが同じ →
さまざまなグラフについての最大流 (蟻本p192)
複数の始点・終点が存在する場合
super-source・super-sink をつくればよい.これは最大流に限った話ではなく最短経路などのグラフの問題一般でよくでてくる.多品種フロー(効率的にはとけない)との混合に注意.
多品種フロー: 始点からは終点に行くなど,始点と終点に対応関係が存在するもの
例題(フローではないけどこのテクを使う)
無向グラフ
両方向に有向辺を貼ったグラフで考えればいい
頂点容量
頂点を入頂点と出頂点に分割し,に入る辺は入頂点,から出る頂点は出頂点へと接続する.入頂点から出頂点への辺の容量を頂点の容量とすることで辺容量に置き換えられる.
最小流量制約
辺に最小流量の制約が存在する場合の最大フローの求め方
頂点を新たに作成する.辺が存在する場合,からに容量,からに容量,からに容量の有向辺を貼る.からへ,からへの有向辺を貼る.からへの最大流をとすると元のグラフの最大流は
からにフローが流れていればへ流量1が入ることが確定するため最小流量制約はクリアしている.
からへフローを流すことでに流量1が確定して流れるようなグラフを構成している.
存在しない場合のcheck
から,からへの有向辺をはらずずにからへ容量の辺を貼る.からへ流量が流れるか?
これがクリアできる からの辺のフローが全て流れている
クリアできないグラフは上の画像のように弾かれる
最小流量制限付き最大流 by snukeさん
から,からの辺を貼らずにの最大流を順番に流す方法が簡単.
グラフを変形
容量を増やす場合 → そのまま流せばいい
辺の容量を1減らす → ならそのまま,それ以外なら残余グラフで押し戻す
詳しくは問題例のBox Witchのあたりに書いた
容量が負
NP-hardなので難しいが変形で消せる場合もある
最小費用流
始点から終点に水を流す問題に見えがちだが,定義上始点と終点は不必要
最小費用流の負辺除去 by snukeさん
LPで定義する
双対性 by wataさん のp43に詳しい
変数定義
有向グラフ
各辺 に対して
- 容量
- コスト
需要供給関数
それぞれ頂点から出る/入る辺の集合
イメージ
の頂点では水が湧き出る
の頂点では水が入る量=出る量
の頂点では水が不足
辺はまで流せ,流量1ごとにコストがかかる
定式化
実装については 最小費用流の負辺除去 by snukeさん に載っている
蟻本形式の実装の場合
* が正: からへ容量コスト0の辺
* が負: からへ容量コスト0の辺とすればよい
始点から終点へ流量を流す → と帰着できる(はず)でよく見るのと同義
最短路反復法
最小費用流を求めるアルゴリズムの一つ
参考資料
- ネットワークフロー入門 by hosさん のp56
- 蟻本p200
辺容量と流量は整数,入力に負閉路は存在しないとする
残余グラフ: である辺はコスト,である辺の逆辺はコスト
流量が以下の間以下を繰り返す
- 残余グラフでまだ流せる辺のみを使ってコストを重みとした最短路問題を解く
- 最短路が存在しなければ流量のフローが存在しない
- 最短路に沿ってフローを目一杯流す
負辺があるため最短路をBellman-Fordで求めると
証明の方針) 残余グラフに負閉路が存在しない 残余グラフに対応するフローが最小費用流
アルゴリズム終了時に負閉路は存在しない
ポテンシャルを考えると負辺が存在するグラフもdijkstraで解ける →
入力に負辺がある場合,一回目だけBellman-Fordをすればよい →
負閉路が存在しているならばBellman-Fordで検出し,そこに目一杯流すと負閉路を消せる これよくわかってない
これは流量に比例する計算量なので擬多項式時間アルゴリズム
最小費用最大流の悪例題 by Min_25さん に指数時間かかる例がある
---ToDo---
別のアルゴリズム
- 容量スケーリング
- 最小平均長閉路解消
- コストスケーリング
---ToDo---
さまざまなグラフについての最小費用流 (蟻本p204)
複数の始点・終点が存在する場合
最大流と同じ super-source・super-sinkを使えばいい
頂点容量
最大流と同じ 頂点を2倍にして辺容量にする
無向グラフ
頂点2倍
最小流量制約
に最小流量が存在する場合辺を追加する
は十分大きな定数
このグラフでの最小費用流 が答えになる
のコストの方が非常に小さいのでの分は必ず流れる
流せない辺があったら答えが以上にになるからわかる(はず)
流す流量が任意
負辺を含むグラフでできるだけ小さくしてくださいみたいな問題
最短経路にフローを流して,最短路が短くなることはない
からまでの最短距離が負の間流し続ければよい
負辺の除去
応用例
マッチング・辺カバー・安定集合・点カバー
二部グラフの最小点被覆、最大安定集合 (最大独立集合)、最小辺被覆を総整理! by drkenさん
GabowのEdmonds' Algorithm(一般マッチング O(VElogV))の解説と実装
一般マッチングは多項式時間で求まる(がめっちゃ複雑)
マッチングの大きさのみで復元がいらないならばTutte行列を使ってで求まる 提出
project selection problem・燃やす埋める問題
問題例
主に 競技プログラミングにおける最大流問題まとめ by hamayanhamayanさん を解いています
最大流
verify用の問題
ARC074 F - Lotus Leaves
最小カットそのまま
No.177 制作進行の宮森あおいです!
最大フローに帰着する https://yukicoder.me/submissions/390377
No.654 Air E869120
各街について時刻の分頂点をつくれば最大フローで解けるがこれは無理
各町に関連する時刻は飛行機が出発/到着する時刻のみなので座圧すれば問題ない
https://yukicoder.me/submissions/390383
CodeChef Bipartite Graph from Trees
概要
頂点の木,個の頂点集合が与えられる
二部グラフを考える
の祖先が頂点集合に含まれる場合とをつなぐ辺を追加する
の最大マッチングを求めろ
解説
二部グラフの辺を定義通りに追加すると程度になり間に合わない
の要素である頂点の子孫全てに辺を貼る部分をどうにかして辺を減らしたい
木の親から子に容量の辺を貼って置くことで子孫に貼る必要はなくなる
頂点数で辺数まで削減できたのでdinic等で最大フローを求められる
Codeforces Round #304 (Div. 2) E. Soldier and Traveling
概要
頂点辺の無向グラフが与えられる
頂点には最初人が存在し,各人は高々一つまでの辺を使って移動ができる(留まることもできる)
移動後に頂点に人が存在するような移動は存在するか?
存在する場合移動の方法の復元も含めて出力しろ
解説
移動前を表す頂点,移動後を表す頂点,始点,終点の計頂点を用意する.
- 始点からの番目の頂点へ容量の辺
- の番目の頂点から終点へ容量の辺
- 入力のグラフでからへ移動可能ならば,の番目の頂点からの番目の頂点へ容量の辺
かつ 始点から終点への最大流がと一致するならばYES
の番目の頂点からの番目の頂点へ流量のフローが流れているならばからへ人が移動した(留まった)と言える
Waiwai Otaku Panic
最短経路のみを考えるので入力のグラフを最短路DAGに変形する
最短路DAG: ある終点への最短路に使われうる辺のみを抽出したグラフ DAGになる
頂点0からの最短経路長が一致しない頂点からスタートする車はある辺を同じタイミングで移動することはない
したがって最短経路長ごとに頂点を分割して考える
集合 を最短経路長が の頂点の集合 とする
super-sourceからの頂点へ容量の辺を貼る
最短路DAGの辺を容量とする(同時に通らないように)
このグラフの最大流を求め,と一致するならばok
全てのに対してこの操作を行う
https://www.hackerrank.com/contests/camypapercon02/challenges/waiwai-otaku-panic/submissions/code/1317045120
Infinite Network
よりもしくはもしくはもしくはの点集合とするにウイルスが来なければ有限個に抑えられる
- 始点から感染したコンピューターへ容量
- から終点へ容量
- 隣り合ったコンピュータ同士で容量
このグラフで最小カット(=最大フロー)を求めればよい https://www.hackerrank.com/contests/unkoder-06/challenges/infinite-network/submissions/code/1317047943
KUPC2016 E - 柵 / Fences
Infinite Networkと大体同じ
切断する部分がマスで頂点なので頂点条件から辺条件に置き換える必要がある
頂点制約と同様に各マスに2つ頂点を用意し,それぞれマスに入る/出る頂点とすればよい
https://atcoder.jp/contests/kupc2016/submissions/8008433
TTPC2015 L - グラフ色ぬり
青い辺を追加しても最大流が増えない 追加した辺集合の任意の辺があるカットに含まれない
カットとして青い辺が含まれる数が最小になるカットを求め,それ以外の青い辺を追加すると考えればよい
カットに含まれる青い辺を減らすには赤い辺の容量を増やして,最小カット(=最大フロー)を求めればよい
https://atcoder.jp/contests/ttpc2015/submissions/8011585
ARC031 D - 買い物上手
変数
- : 番目の組合せでもらえる経験値 (入力)
- : 番目のアイテムの値段 (入力)
平均の最大化は二分探索が典型
得た経験値使った金とする.得た経験値使った金であるを求めればよい.よって得た経験値使った金を最大化できればよい.この問題をIPで定式化する.
変数
- : 得た経験値使った金 (given)
- : 番目の組合せを取得するか?の01変数
- : 番目のアイテムを買うか?の01変数
(番目の組合せにアイテムが含まれる)
は不等式ではないが と等価なのでIPと言える.一般に (ならば) を数理計画で扱いたいときはbig-M法などを用いることで不等式に変換することができることがある.
より は連続変数(実数値を取る変数)としても答えが悪化しない.したがってIPからLPに変形することができた.01変数や整数変数などを連続変数にすることを連続緩和と呼ぶ.
変数
- : の連続緩和
- : の連続緩和
(番目の組合せにアイテムが含まれる)
このLPの双対問題を考える.
-----わからん-----
双対性 by wataさんのp14~に沿って変形をする. の両辺に , の両辺に を掛けて足し合わせる. となる.元問題の目的関数の係数と比較すると となる.
(番目の組合せにアイテムが含まれる)
どうやってもこのpdfの変形と一致しないけど 最初の制約式じゃなくて=なのなんで? の消し方もよくわからん http://www.orsj.or.jp/~archive/pdf/bul/Vol.42_06_440.pdf
-----わからん-----
(番目の組合せにアイテムが含まれる)
これは二部グラフの最大流と同義
経験値を得られる組合せに対応する個の頂点,アイテムに対応する個の頂点,始点,終点の個の頂点からなるグラフを考える.
- 始点から組合せに容量
- アイテムから終点に容量
- 組合せからアイテムに容量 (アイテムが組合せに含まれる)
この最大流が
- 以上ならが小さい
- 未満ならが大きい
として二分探索
https://atcoder.jp/contests/arc031/submissions/8015301
Educational Codeforces Round 8 F. Bear and Fair Set
概要
Limakは要素(は5の倍数)の集合を持っている
この集合の要素は1以上以下である
要素をした値が0,1,2,3,4のものがそれぞれ個含まれる
1以上以下の要素が個含まれるというヒントが個与えられる
ヒントに矛盾しない集合が存在するかどうか?の判定を行え
解説
ヒントについてでソートすることで,区間に何個要素が存在するか?と変形できる
この時点で矛盾が存在する場合"unfair"を出力して終了する
区間と余り0~4で対応をつける
区間個,余り0~4の5個,始点,終点の計頂点から成るグラフを考える
このグラフで最大流がならば"fair",それ以外なら"unfair"を出力する
RUPC2018 day3 F: 最短距離を伸ばすえびちゃん
最短経路について考えるので最短路DAGに変形する
最短距離を伸ばす場合,最短路DAGのカットの辺を1ずつ伸ばせば最短距離が1伸びる
したがって容量をとした有向辺を貼り,最小カットを求めればよい
https://onlinejudge.u-aizu.ac.jp/beta/review.html#RitsCamp18Day3/3939898
AOJ2168 Luigi's Tavern
マッチングをグラフで表して最大流を求める
http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3940110#1
AOJ2168 Luigi's Tavern by nanikakaさん
AOJ2835 敵襲から守れ
辺容量が1の辺を無視したグラフで最小カットを求めればよい.しかし,愚直にやると最大流の計算を回やることになって間に合わない.そこで,蟻本p193のグラフを変形する場合に書かれているテクニックを使う.
まず入力のグラフについて最大流を求めておく.次に容量が1の辺の容量を0にした後,最大流を計算する.この最大流が入力のグラフの最大流よりも小さければ,それが達成できる最小である.
容量を1減らしたときの最大流の再計算は以下の3パターンのいずれかで計算できる
- 辺について
そのまま辺容量を1減らす - かつ (からに残余グラフでパスが存在 からへ流量1のフローが流せる)
からへ押し戻せばよく,最大流の値は変化しない(画像1枚目) - otherwise
からとからへ押し戻せばよい.最大流の値は1減少(画像2枚目)
よくあるフローの実装では辺にcapとして,逆辺にcapとしてをもたせる.このとき辺容量を1減らすという操作は以下の2パターンのいずれかとなる.
がともにマイナス1される.よって逆辺のcapをマイナス1すればよい.
のみマイナス1される.よって辺のcapをマイナス1すればよい
http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3941579#1
AOJ2313 Box Witch
敵襲から守れと同様にグラフを変形する場合に最大流を高速に計算する方法を用いる.
辺を増やすことは辺容量が0から1にすると言い換えられる.辺容量を増やしたあと,0から最大流を計算するのではなく流量1のフローを流すことで最大流を計算できる.流量1のフローはBFS,DFSを1回行えばよいのでで計算可能である.
容量を減らす場合は敵襲を守れと同様に計算すればよい.
http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3941573#1
辺容量を変化させたときに最大流を再計算する方法
- 辺容量をプラスする場合
単純に始点から終点へフローを流せばよい
流量ならばとかになるのかな…? - 辺容量をマイナス1する場合
でできる - 辺容量をマイナスする場合
残余グラフでからのパスでできるだけ押し戻しておく
これで押し戻せなかった分をから,からに押し戻す
とかでできる?(ちゃんと確かめてはない)
変化量がより大きい場合を問題として面白くするの難しそう
蟻本p193の「最大流のフローが辞書順最小」を最大流に含まれる辺番号の集合が辞書順最小の意味だと思うと,辺番号が最も大きいものの容量を1減らして最大流が減少しなければ,改善されているみたいなのを繰り替えすってことな気がする
yukicoder No.459 C-VS for yukicoder
パックと列のマッチングに帰着すると最小流量制限つき最大流で求められる.
https://yukicoder.me/submissions/392121
最大流について
- グラフをうまく構築して辺の数を減らす
- 頂点制約を辺制約に置き換える
- 最大フロー・最短距離を増やす → 最小カットの辺を増やす
- 複数の集合のマッチングをグラフでうまいこと表現
- グラフを変形した際に最大流を高速に再計算
あたりの問題があった
ここからは 競技プログラミングにおける最大マッチング問題まとめ by hamayanhamayanさん を主に解いています
yukicoder No.241 出席番号(1)
流量が1の辺が最大二部マッチングに含まれるので,二部マッチングの復元ができる.
https://yukicoder.me/submissions/392650
yukicoder No.421 しろくろチョコレート
幸福度が増える量から,方法3,2,1と貪欲に行っていけば良い.方法3で取れるペアが何個あるかわかれば,最大の幸福度がわかる.グリッドグラフは二部グラフであるので,ペアの個数は二部マッチングを用いて数えられる.
https://yukicoder.me/submissions/392796
天下一プログラマーコンテスト2015予選A C - 天下一美術館
しろくろチョコレートとほとんど同じ.隣接している && a[i1][j1]!=b[i1][j1] && a[i2][j2]!=b[i2][j2] && a[i1][j1]!=a[i2][j2] であるような のペアが何個あるか数えられればよい.グリッドグラフは二部グラフなので二部マッチングで数えられる.
https://atcoder.jp/contests/tenka1-2015-quala/submissions/8115586
AtCoder Regular Contest 013 D - 切り分けできるかな?
つくることが可能な体積を列挙する.基本的に一つの鉄塊から1つの体積を生成できるため,つくれる体積の種類数 2が答えになる.ただし,一つの鉄塊から使える体積の鉄塊を2つ得た場合,切る必要のある鉄塊が一つ減る.この鉄塊の数を減らせる体積のペアの数を求めたい.
ある鉄塊から体積 と体積 の鉄塊が作れるならば, と を結んだグラフをつくり二部マッチングを求める.このマッチングが鉄塊を減らせる個数になる.
https://atcoder.jp/contests/arc013/submissions/8116019
CSA Flipping Matrix
概要
の行列が与えられる.以下の操作を繰り返して,全ての対角成分が1である行列にできるか?できるならば操作の復元も出力せよ.
- 行を入れ替える
- 列を入れ替える
解法
左側に行を表す 頂点,右側に列を表す 頂点がある二部グラフを考える.行列の に1が存在するなら行 と列 を結ぶ.この二部グラフで最大マッチングが でない場合,対角成分が全て1の行列をつくるのは不可能である.
二部マッチングの復元を行い,対応する行と列を求める.この対応にのっとって,列の交換を行っていくことで操作の復元が可能である.
https://csacademy.com/code/4FNXQBaB/
CSA No Prime Sum
概要
個の異なる要素からなる集合 が与えられる.任意の2要素の和が素数でないようにするために取り除く要素数のうち最小のものを求めろ.復元もすること.
解法
が素数であれば頂点 と頂点 を結んだグラフを考える. より素数は奇数しかありえない.したがって偶数と奇数の間にしか辺は存在しないので,これは二部グラフである.
このグラフで辺の端点のうち片方の頂点は少なくとも消去しなければならない.これは最小点カバーで,二部グラフであれば高速に求めることができる.最小点カバーの復元は残余グラフで「到達不可能な左側頂点」「到達可能な右側頂点」とすればよい.
二部グラフの最小点被覆、最大安定集合 (最大独立集合)、最小辺被覆を総整理! by drkenさん
https://csacademy.com/code/EVEX24Mx/
HackerRank Drawing Rectangles
概要
左下が ,右上が である四角形の領域 個に色を塗る.行/列の色を全て消す操作を繰り返し,全ての色を消す.このときの最小の操作回数,およびどのような操作をするか出力せよ.
色が塗られているマスの数
解法
左側に行を表す頂点,右側に列を表す頂点を用意した二部グラフを考える.マス に色が塗られているならば,行 と列 を表す辺をつなぐ.このグラフで最小点カバーを求めることで答えがわかる.
最大でも 程度なので dinicで で最大マッチングを求めることができる.
色がついているマスを列挙するパートはセグメント木を持ちながら平面走査を行うことでできる.セグメント木で のときの情報を 座標で色が何重に塗られているか として持つ. である を列挙すればよい.
Maximum-Cup 2018 H - Maxmin Tour
最大値の最小化なので二分探索で判定問題に置き換える. となるような移動だけでスタンプラリーが可能か?の判定に置き換えることができた.
そもそも から までの距離が 以下であれば無条件でこの移動は可能.
魔法の石は から までの間で高々1回しか使用しない.また使用する場合, にいるときに使うべきである.よって,「魔法の石 を使うことで から への移動が距離 以下でできるようになる」と「 から までの距離が 以下」は同値である.
地点を表す 個の頂点と魔法の石を表す 個の頂点からなる二部グラフを考える.「 から までの距離が 以下」であれば,地点 と魔法の石 を結ぶ.この二部グラフの最大マッチングが ならば移動が可能と判定できる.
https://atcoder.jp/contests/maximum-cup-2018/submissions/8124730
AOJ2429 まるかいて
初期盤面を全て空白である盤面に帰着する.いったん全ての丸を消去したことにして,その消去コストの和を求めておく.あるマスに丸が存在するようにするには,以下のコストがかかる.
- 元々空白,書き込みコストの分を足す
- 元々丸,消去コストの分を引く
行を表す 個の頂点,列を表す 個の頂点が存在する二部グラフを考える. を丸にするために必要なコストを重みとした辺を行 と列 の間に結ぶ.この二部グラフで重み付き最小二部マッチングを求めればよい.
重み付き最小二部マッチングは最小費用流で求められる.
http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3952428#1
Educational Codeforces Round 29 F. Almost Permutation
概要
要素の配列 について 個の情報が与えられる
- ] について
- ] について
配列で が存在する数を とする. 個の情報に矛盾せずに を最小化しろ.ありえない場合は-1を出力せよ.
解法
始点 → 配列の 要素に対応する 頂点 → の値に対応する 頂点 → 終点と並べたグラフを用意する.
「始点 → 配列の 要素に対応する 頂点」の辺は容量1,コスト0とする.
「配列の 要素に対応する 頂点 → の値に対応する 頂点」の辺は配列の 番目が取りうる値の範囲に応じて,容量1コスト0 の辺を張る.
「 の値に対応する 頂点 → 終点」の辺を使って を表現する. なので である.よって,容量が1でコストが であるような辺を張ればよい.
このグラフで流量 の最小費用流を求めれば良い.