ひとりで勝手にはじめた蟻本読書会 最大流問題と最小カット問題 蟻本読書会 の続きです。

最小費用流問題とは、流す量が与えられた際、流すために掛かる総費用を最小にするためにはどのようにするとよいのかを決定する問題です。

最小コストを調べる
そのパスに流せるだけ流す
辺の容量と逆辺の容量を更新する

与えられたフローに達するまで上記を繰り返すことで解を得ることができます。

F – 最小費用流

F – 最小費用流

V 個の街があります。各街には 1, 2, …, V と番号が付いています。E 本の水道管があり、i 本目の水道管は街 u_i から街 v_i へ水を最大で c_i だけ流すことができますが、水を 1 流すごとに費用が d_i かかります。街 1 から街 V へ水を F だけ流すとき、合計費用の最小値を求めてください。

入力されるデータ
V E F
u_1 v_1 c_1 d_1
u_2 v_2 c_2 d_2

u_E v_E c_E d_E

(ただし、
1 ≦ V, E ≦ 100, 1 ≦ F ≦ 10^9
1 ≦ u_i, v_i ≦ V, 1 ≦ c_i, d_i ≦ 10^9 )

最大流問題と同じように逆辺をつくります。そして逆辺のコストは辺のコストの符号を反転させたものにします。頂点 A から 頂点 B へ容量 c、コスト d の辺を張ったら、頂点 B から 頂点 A へ容量 0、コスト -d の逆辺を張ります。それから問題文には「多重辺は存在しない」とは書いていません。何度やっても WA(wrong answer)が 2 件でるのでおかしいと思っていたら「多重辺は存在しない」という勝手な前提でコードを書いていた鳩のミスでした。

Edgeクラスを定義するときに逆辺がすぐに取得できるように Reverse というプロパティを定義しています。

またコストが負数の辺が存在するのでダイクストラ法が使えません。ここではベルマンフォード法でコストが最小になる経路を求めています。負閉路のチェックもしていますが、実際に負閉路ができることはないみたいです。