思路:
容易把答案转化为
∑
s
i
w
i
+
∑
t
i
(
w
x
−
w
y
)
\sum{s_iw_i}+\sum{t_i(w_x-w_y)}
∑siwi+∑ti(wx−wy),然后我们设初始代价为
−
∑
∣
s
i
∣
w
i
-\sum{|s_i|w_i}
−∑∣si∣wi,然后考虑建模。
如果Si大于0,则源点向i连一条流量为2SiW的边,代表割掉这条边(也就是让i为w)要多付出的代价,向汇点连0的边。Si小于0,汇点向i连2SiW的边,向汇点连0的边。
然后对于wx-wy,则直接连2wti的双向边。
考虑限制,若果是<,则强制x和y的w,分别连inf边。
如果是=,则之间连inf边
如果是<=,则y向x连inf边。
然后做最小割就是答案。
c o d e code code
#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
#include <cstring>
#define ll long long
using namespace std;
const ll MAXN = 550, inf = 1e12;
ll Q, tot;
ll n, w, p, q, S, T;
ll s[MAXN * 3], a[MAXN * 3];
ll crn[MAXN * 3], dep[MAXN * 3], head[MAXN * 3];
struct edge {
ll to, next, w, op;
} b[MAXN * MAXN * 21];
ll MB[MAXN][MAXN];
queue<ll> G;
void add(ll x, ll y, ll w) {
b[++tot] = (edge){ y, head[x], w, tot + 1 };
head[x] = tot;
b[++tot] = (edge){ x, head[y], 0, tot - 1 };
head[y] = tot;
}
bool bfs() {
for (int i = 1; i <= T; i++) crn[i] = head[i], dep[i] = 0;
while (!G.empty()) G.pop();
G.push(S);
dep[S] = 1;
while (!G.empty()) {
int now = G.front();
G.pop();
for (int i = head[now]; i; i = b[i].next)
if (b[i].w && !dep[b[i].to]) {
dep[b[i].to] = dep[now] + 1;
if (b[i].to == T)
return 1;
G.push(b[i].to);
}
}
return 0;
}
/*
ll dfs(ll x, ll flo) {
if(x == T) return flo;
ll d = flo;
for(ll i = crn[x]; i; i = b[i].next) {
crn[x] = b[i].next;
ll y = b[i].to;
if(dep[y] == dep[x] + 1 && b[i].w > 0) {
ll tmp = dfs(y, min(d, b[i].w));
b[i].w -= tmp;
b[i ^ 1].w += tmp;
d -= tmp;
if(d == 0) break;
}
}
return flo - d;
}
*/
ll dfs(int now, ll sum) {
if (now == T)
return sum;
ll go = 0;
for (int i = crn[now]; i; i = b[i].next)
if (b[i].w && dep[now] + 1 == dep[b[i].to]) {
ll this_go = dfs(b[i].to, min(sum - go, b[i].w));
if (this_go) {
b[i].w -= this_go;
b[b[i].op].w += this_go;
go += this_go;
if (go == sum)
return go;
}
}
dep[now] = -1;
return go;
}
ll dinic() {
ll ans = 0;
while (bfs()) {
ans += dfs(S, 1e18);
}
return ans;
}
void clean() {
tot = 0;
memset(head, 0, sizeof(head));
memset(MB, 0, sizeof(MB));
memset(b, 0, sizeof(b));
memset(s, 0, sizeof(s));
}
int main() {
freopen("variable.in", "r", stdin);
freopen("variable.out", "w", stdout);
scanf("%lld", &Q);
while (Q--) {
scanf("%lld%lld%lld%lld", &n, &w, &p, &q);
for (ll i = 1; i <= n; i++) s[i] = 1;
S = n + 1, T = n + 2;
for (ll i = 1; i <= p; i++) {
ll r1, r2, r3, r4, r5, r6, r7, r8, r9;
scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld", &r1, &r2, &r3, &r4, &r5, &r6, &r7, &r8, &r9);
MB[r1][r2] += r4;
MB[r2][r3] += r5;
MB[r3][r1] += r6;
s[r1] += r7 - r9, s[r2] += r8 - r7, s[r3] += r9 - r8;
}
ll low = 0;
for (ll i = 1; i <= n; i++) {
low += abs(s[i]);
if (s[i] > 0)
add(S, i, 2 * s[i]);
if (s[i] < 0)
add(i, T, -2 * s[i]);
for (int j = i + 1; j <= n; j++) {
if (MB[i][j] + MB[j][i])
add(i, j, MB[i][j] * 2 + MB[j][i] * 2), add(j, i, MB[i][j] * 2 + MB[j][i] * 2);
}
}
for (ll i = 1; i <= q; i++) {
ll r1, r2, r3;
scanf("%lld%lld%lld", &r1, &r2, &r3);
if (r3 == 0)
add(r2, r1, inf);
if (r3 == 1)
add(r1, r2, inf), add(r2, r1, inf);
if (r3 == 2)
add(S, r1, inf), add(r2, T, inf);
}
printf("%lld\n", dinic() * w - low * w);
clean();
}
return 0;
}