最小割
思路:总的权值和 - 最小割 = 最大权值建图:
对于边(u, v),从源点s向u建一条边,从u向汇点t建一条边,两条边分别表示点u的两个职位,v同理。u和v互相建一条双向边。根据上面的思路,对于每一条边的取值,我们要满足边的权值和减去最小割是我们要求的最大权值。
分别给边编号
a: (s, u), b: (s, v), c: (u, t), d:(v, t), e: (u, v),(v, u)。
权值和sum = A+B+C, A是同为Warriors的权值,B是不同职位的权值,C是同为Mages的权值。
假设只存在一条关系边 (u, v),根据上面的方法建图,可能存在的最小割是
(a+b), (c+d), (a+e+d), (b+e+c)
只要边权的取值满足:
a+b = B+C (sum-(B+C) = A, 同为Warriors)
c+d = A+B (sum-(A+B) = C, 同为Mages)
a+e+d = A+C (sum-(A+C) = B, 不同职位)
b+e+c = A+C (sum-(A+C) = B, 不同职位)
解方程后得出 a = b = (B+C)/2, c = d = (A+B)/2, e = -B+(A+C)/2。
因为题目给出 3|c, 所以权值赋值的时候都要同乘一个2,输出答案的时候再除回来。
#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
typedef long long ll;
const int MaxnN = 500+10;
const int MaxnE = 1e5+10;
const int INF = 0x3f3f3f3f;
const long long LINF = 1e18;
struct Edge {
int v, next;
ll cap, flow;
} edge[MaxnE<<1];
int h[MaxnN], edge_cnt;
int n, m;
int deep[MaxnN], cur[MaxnN];
inline void add(int u, int v, int c) {
edge[edge_cnt].v = v;
edge[edge_cnt].cap = c;
edge[edge_cnt].flow = 0;
edge[edge_cnt].next = h[u];
h[u] = edge_cnt++;
edge[edge_cnt].v = u;
edge[edge_cnt].cap = 0;
edge[edge_cnt].flow = 0;
edge[edge_cnt].next = h[v];
h[v] = edge_cnt++;
}
inline bool bfs(int s, int t) {
for(int i = s; i <= t; ++i) deep[i] = 0;
deep[s] = 1;
queue <int> qu;
qu.push(s);
while(!qu.empty()) {
int u = qu.front(); qu.pop();
for(int i = h[u]; i != -2; i = edge[i].next) {
Edge e = edge[i];
if(deep[e.v] == 0 && e.cap > e.flow) {
deep[e.v] = deep[u]+1;
qu.push(e.v);
}
}
}
return deep[t] > 0;
}
inline ll dfs(int u, ll a, int t) {
if(u == t || a == 0) return a;
ll flow = 0, f;
if(cur[u] == -1) cur[u] = h[u];
for(int &i = cur[u]; i != -2; i = edge[i].next) {
Edge &e = edge[i];
if(deep[e.v] == deep[u]+1 && (f = dfs(e.v, min(a, e.cap-e.flow), t)) > 0) {
e.flow += f;
edge[i^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
inline ll max_flow(int s, int t) {
ll flow = 0;
while(bfs(s, t)) {
for(int i = s; i <= t; ++i) cur[i] = -1;
flow += dfs(s, LINF, t);
}
return flow;
}
int main(void)
{
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 0; i <= n+1; ++i) h[i] = -2;
edge_cnt = 0;
int s = 0, t = n+1, u, v, aa, bb, cc;
ll ans = 0;
for(int i = 0; i < m; ++i) {
scanf("%d%d%d%d%d", &u, &v, &aa, &bb, &cc);
aa *= 2; bb *= 2; cc *= 2;
add(s, u, (aa+bb)/2);
add(s, v, (aa+bb)/2);
add(u, t, (cc+bb)/2);
add(v, t, (cc+bb)/2);
add(u, v, (-bb+(aa+cc)/2));
add(v, u, (-bb+(aa+cc)/2));
ans += aa+bb+cc;
}
ans = ans-max_flow(s, t);
printf("%lld\n", ans/2);
}
return 0;
}
浙公网安备 33010602011771号