問題はこちら
問題概要
頂点辺の有向グラフがあり,人が人ずつ頂点から辺を辿って任意の回数繰り返す.人が人以上通った頂点のの値の総和の最大値を求めよ.解説
ある強連結成分を通るときはその強連結成分の全頂点を通るべきなので強連結成分分解してDAGにする.以降はDAGで解く.各頂点から新たに作った頂点に有向辺を張る.このグラフにおける頂点から頂点への本のパスに含まれる頂点のの和の最大値が答え.
問題が最小費用流っぽい.最大化だったり,頂点にコストがあったりするが実は最小費用流のアルゴリズムで解ける.
最大化を最小化にするためにをにする.負のコストをもつ辺ができるが,これは後で処理する.
頂点のコストは,頂点毎に以下のように頂点を2つ作る.この頂点を通るフローは必ず下図の2頂点の間の辺を通るのでこのように辺のコストに変換することができる.
複数回頂点を通っても最初の回しかコストが発生しない.これは上記の2頂点間に「容量,コストの辺」と「容量(実装ではでいい),コストの辺」を張ることで実現できる.優先的にコストの辺から使われるのでこの方法でよい.
こうしてできたグラフの頂点から頂点へ流量を流すときの最小コストが答えとなるが,負のコストをもつ辺があるので非負コストの辺のみからなるグラフの最小費用流に言い換える必要がある.
- 辺に適切に定数を足す.
- あらかじめ負のコストを持つ辺に最大までフローを流す.
- 最短距離を求めるアルゴリズムを用いてポテンシャルを初期化する(アリ本に説明アリ).
1は公式解説の方法であり,問題ごとに考える必要がある(ライブラリ化難しそう?).2は今回の問題だと全頂点に負のコストがあるので流すフローが多くなり間に合わない.3は負のコストがあるグラフの最短距離を求めるアルゴリズムであるBellman-Fordを用いるとかかり間に合わないが,グラフがDAGであることを利用してトポロジカル順にDPすることで最短距離がで求められる.
提出プログラム
https://atcoder.jp/contests/abc214/submissions/25067496感想
Gより典型度高い.最小費用流の負辺除去は1の方法でやろうとするとこんがらがる.