题目大意: 有一个长度为n的
w
数组,
思路: 考虑最小割模型。 若设 xi=0 表示i与源点连通, xi=1 表示i与汇点连通。 则最小割= min{∑(u,v)max(xv−xu,0)∗c} , c为对应边的流量。
观察题目中的式子可以发现, |a−b|+(a−b)=2max(a−b,0) 。 经过一番转换, 要求的表达式可以转换成只含 2∗max(wi−wj,0) 和 wi 的式子(前面还带些系数)。
考虑用最小割来表示这些式子。用 xi=0 表示 wi=−W , xi=1 表示 wi=W 。
则 2∗a∗max(wi−wj,0)=4∗a∗W∗max(xi−xj,0) , 即j向i连一条流量为 4∗a 的边。(由于每条边的流量上都有个W,所以可以最后再乘)
若 a>0 , 则 a∗wi=2∗a∗W∗max(xi−0,0)−a∗W , 即s向i连一条流量为 2∗a 的边, 答案初始值加上 −a 。
若 a<0 , 则 a∗wi=2∗(−a)∗W∗max(1−xi,0)−(−a)∗W , 即i向t连一条流量为 −2∗a 的边, 答案初始值加上 −(−a) 。
再考虑那q条限制。
若
wi≤wj
, 只有
xi=1
且
xj=0
时才会违反条件, 即
max(xi−xj,0)∗inf
, j向i连一条流量为inf的边。
若
wi=wj
, 可以转换为
xi≤wj
且
wj≤wi
。
若
wi<wj
, 可以转换为
xi≤0
且
1≤wj
。
最后的答案即为最小割*W。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = (int)1e4 + 10;
const int M = (int)1e6 + 10;
const int inf = 1 << 30;
int n, W, p, q, s, t, aoe[N];
int cnt, lst[N], nxt[M], to[M], f[M];
void add(int u, int v, int flow){
nxt[++ cnt] = lst[u]; lst[u] = cnt; to[cnt] = v; f[cnt] = flow;
nxt[++ cnt] = lst[v]; lst[v] = cnt; to[cnt] = u; f[cnt] = 0;
}
int head, tail, que[N], d[N];
bool bfs(){
head = tail = 0;
que[tail = 1] = s;
for (int i = 1; i <= t; i ++) d[i] = 0; d[s] = 1;
while (head < tail){
int u = que[++ head];
for (int j = lst[u]; j; j = nxt[j]){
int v = to[j];
if (d[v] || !f[j]) continue;
d[v] = d[u] + 1; que[++ tail] = v;
}
}
return d[t];
}
int dfs(int u, int flow){
int ret = 0, a;
if (u == t) return flow;
for (int j = lst[u]; j; j = nxt[j]){
int v = to[j];
if (!f[j] || d[v] != d[u] + 1) continue;
if (flow && (a = dfs(v, min(f[j], flow)))){
flow -= a, ret += a;
f[j] -= a, f[j ^ 1] += a;
}
}
return ret;
}
int main(){
int T; T = 0;
for (scanf("%d ", &T); T --; ){
scanf("%d %d %d %d", &n, &W, &p, &q);
cnt = 1;
s = n + 1, t = s + 1;
for (int i = 1; i <= t; i ++) lst[i] = 0;
for (int i = 1; i <= n; i ++) aoe[i] = 0;
while (p --){
int x, y, z, a, b, c, d, e, f;
scanf("%d %d %d %d %d %d %d %d %d", &x, &y, &z, &a, &b, &c, &d, &e, &f);
add(y, x, 4 * a);
add(z, y, 4 * b);
add(x, z, 4 * c);
aoe[x] += (d - a) - (f - c);
aoe[y] += (e - b) - (d - a);
aoe[z] += (f - c) - (e - b);
}
for (int i = 1; i <= n; i ++) aoe[i] ++;
int ans = 0;
for (int i = 1; i <= n; i ++){
if (aoe[i] > 0){
add(s, i, 2 * aoe[i]);
ans -= aoe[i];
}
if (aoe[i] < 0){
add(i, t, -2 * aoe[i]);
ans -= -aoe[i];
}
}
while (q --){
int x, y, r;
scanf("%d %d %d", &x, &y, &r);
if (r == 0) add(y, x, inf);
if (r == 1) add(y, x, inf), add(x, y, inf);
if (r == 2) add(s, x, inf), add(y, t, inf);
}
while (bfs()) ans += dfs(s, inf);
printf("%lld\n", 1LL * ans * W);
}
return 0;
}