TOP > メモ
燃やす埋める問題
概要
以下の制約問題は最小カットで解くことが出来る。
- すべての頂点に を割り当てる
- 頂点 が で頂点 が に割り当てられたとき 失う
- 失う重みの和の最小値を求めよ
この問題の解法は以下の通りである。
- 必ず が割り当てられる頂点 , が割り当てられる頂点 を用意する
- 制約 がある → 頂点 から頂点 に容量 の辺を張る
- 頂点 から頂点 への最小カットを求める
また色々な制約を の形に変形することができる( は新しい頂点を別に用意することを表す)。
変形前の制約 | 変形後の制約 |
---|---|
が のとき 失う | |
が のとき 得る | 無条件で 得る |
が のとき 失う | |
が のとき 得る | 無条件で 得る |
がともに のとき 得る | 無条件で 得る |
がともに のとき 得る | 無条件で 得る |
一方で以下の制約があるときは、解くことが基本的には難しい。グラフが 部グラフになっている場合は、一方の頂点の真理値を全て反転させることで、「 が で が のときに 失う」場合に帰着できる場合がある。
変形前の制約 | 変形後の制約 |
---|---|
がともに のとき 失う | - |
がともに のとき 失う | - |
問題例
Educational Codeforces Round 55 G. Petya and Graph
頂点 辺の単純グラフが与えられる。それぞれの頂点と辺には重み が割り当てられている。部分グラフの重みを(辺の重みの和)-(頂点の重みの和) と定義する。部分グラフの最大重みを求めよ。
それぞれの頂点に対して が割り当てられた時に部分グラフに使用すると定義する。
- 頂点 が のとき 失う
- 頂点 がともに のとき 得る
にしたがってグラフを構成すると、答えを求めることができる。
Copy
#include<bits/stdc++.h>
using int64 = long long;
int main() {
int N, M, A[1000];
cin >> N >> M;
Dinic< int64 > flow(N + M + 2);
int S = N + M, T = N + M + 1;
int64 ret = 0;
for(int i = 0; i < N; i++) {
int a;
cin >> a;
flow.add_edge(S, i, a);
}
for(int i = 0; i < M; i++) {
int a, b, c;
cin >> a >> b >> c;
--a, --b;
ret += c;
flow.add_edge(i + N, T, c);
flow.add_edge(a, i + N, flow.INF);
flow.add_edge(b, i + N, flow.INF);
}
cout << ret - flow.max_flow(S,T) << endl;
}