2019年8月18日日曜日

TDPC R - グラフ

有向グラフに2つのパス(ウォーク?)を描いて、できるだけ多くの頂点を被覆する問題。流量2のフローを流す最小費用流問題に帰着する。

ネットワークの作り方を考える。まず、コスト(利得)を与えたいのは頂点なので、すべての頂点vvvinv_{\operatorname{in}}voutv_{\operatorname{out}}に分割する。始点SSから各vinv_{\operatorname{in}}​に容量++\infty・コスト00の辺を張り、voutv_{\operatorname{out}}から終点TTにも容量++\infty・コスト00の辺を張る。また、元のグラフに頂点uuからvvへの辺が存在するならば、uoutu_{\operatorname{out}}からvinv_{\operatorname{in}}​へ容量++\infty・コスト00の辺を張る。

問題になるのは頂点へのコストの与え方で、1つのパスが頂点vvを通ったら11の利得(=1−1のコスト)になるが、もう1つのパスが同じ頂点を通っても利得はない、という条件を再現しなければならない。これは、vinv_{\operatorname{in}}​からvoutv_{\operatorname{out}}​に2つの辺を張ることで実現する。1つの辺は容量11・コスト1−1とし、もう1つは容量++\infty・コスト00とすればよい。

これでネットワークが完成したので、STS \rightarrow Tに流量22のフローを流して最小コストを求めればよい……が、最小費用流のアルゴリズムによっては負閉路をどうするかが問題になる。一番簡単なのは、最初にグラフを強連結成分分解して閉路をすべて1点に潰してしまい、できあがったDAG上で最小費用流を考えることだろう。この時、作るネットワークは上とほとんど変わらないが、頂点をまとめてしまっているので、vinv_{\operatorname{in}}​からvoutv_{\operatorname{out}}へ張る辺のコストは変える必要がある: 一方の辺は容量++\infty・コスト00のままで良く、もう一方は容量11でコストを(元のグラフでvに対応する強連結成分のサイズ)−(元のグラフでvに対応する強連結成分のサイズ)とする。


drkenさんのリストにフローの問題として挙がっていたのだが、自分では辺の張り方がわからなかった。上の方針はyosupoさんの提出に基づいている。