KUPC 2014 I - Rain
問題
n個の地域に雨を同じ量ずつ振らせたい。
雨の降らせ方はm個あって、
i番目の降らせ方ではa[i]番目の地域に2, b[i]番目の地域に0, それ以外の全ての地域に1の雨が降る。
最初、上の降らせかたで、c0, ... , ck-1の雨を降らせた。
この後、どうにかして全ての地域に降る雨の量を同じにしたい。
最小で何回雨を降らせればそれが達成できるか。できないときは-1を出力せよ。
制約条件
n≦10000
m≦20000
k≦15
方針
最小費用流。
等しくするだけなので、雨の量は差分だけを考えてよくて、
i番目の降らせかたはa[i]番目に+1, b[i]番目に-1, 残りの地域を+0としても同じ。
k個の初期雨が終わった時点で、
x0, x1, ..., xn-1の雨になっているとすると、
プラスのところを0まで減らして、マイナスのところを0まで増やす必要がある。
n頂点+ソースとシンクからなるグラフを考える。
プラスのxiには、ソースからコスト0, 流量xiの辺を張って、
マイナスのxiには、シンクへコスト0, 流量|xi|の辺を張る。
b[i]からa[i]にコスト1, 流量無限の辺を張れば、このグラフにΣ|xi|のフローを流すときの最小コストが、必要な雨の回数の最小値である。
グラフが大きいけど、流量が高々15くらいしかないので間に合う。
(15回のダイクストラが間に合えばよい)
ソースコード
int main(){ int n, m, k; cin >> n >> m >> k; vi v(k); vi a(m), b(m), c(m), cnt(n); costflowGraph<int> g(n + 2); int s = n, t = n + 1, f = 0; rep(i, k) cin >> v[i]; rep(i, m){ cin >> a[i] >> b[i] >> c[i]; a[i]--; b[i]--; g.add(b[i], a[i], inf, c[i]); } rep(i, k){ v[i]--; cnt[a[v[i]]]++; cnt[b[v[i]]]--; } rep(i, n){ if(cnt[i] < 0) g.add(i, t, -cnt[i], 0); if(cnt[i] > 0) g.add(s, i, cnt[i], 0), f += cnt[i]; } cout << g.min_cost_flow(s, t, f) << endl; return 0; }