牛客练习赛40 F-小D的剑阵 最小割+二元关系建图

传送门:https://ac.nowcoder.com/acm/contest/369/F

题意

思路

数据范围不大,而且存在二元限制关系,考虑网络流。

假如x和y存在二元限制关系,所以考虑x和y是否选取。

如果考虑选取呢?最小割!设与源点s在一部分的点不取,与汇点在一部分的点取。

将所有的$w$和$v_0$和$v_1$加起来,然后把最小割认为是代价,答案就是sum-最小割(最小代价)。

设$w_x,w_y,v_0,v_1,v_2$表示x的权值,y的权值,x和y都选的权值,x和y都不选的权值,x和y只选一个的权值。

为什么没有$v_2$?因为$v_2$是扣除的,不是代价,$v_2$要在我们最小割模型中会被算进去,最后会减掉。

则对于上面的模型,最小割有四种:

  • $x和y都选,最小割为a+c=v_1$
  • $x和y都不选,最小割为b+d=w_x+w_y+v_0$
  • $x选,y不选,最小割为a+f+d=w_y+v_0+v_1+v_2$
  • $x不选,y选,最小割为c+e+b=w_x+v_0+v_1+v_2$

然后就要构造边的容量了。

b和d分别是连向汇点的边,则为$w_x+\frac{v_0}{2}和w_y+\frac{v_0}{2}$。 a和c分别是连向源点的边,则为$\frac{v_1}{2}和\frac{v_1}{2} 剩下的e和f解出来为$$v_2+\frac{v_0+v_1}{2}$

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
##include "bits/stdc++.h"
using namespace std;

struct Dinic {
static const int N = 1e3 + 10, M = 1e5 + 10, INF 0x3f3f3f3f;
int n, m, s, t;
int maxflow;
int deep[N], cur[N];

struct Edge {
int v, next;
int cap;
}e[M << 1];
int head[M << 1], cnt;

void init() {
memset(head, -1, sizeof head);
cnt = maxflow = 0;
}

void add(int u, int v, int cap) {
e[cnt].v = v;
e[cnt].cap = cap;
e[cnt].next = head[u];
head[u] = cnt++;

e[cnt].v = u;
e[cnt].cap = 0;
e[cnt].next = head[v];
head[v] = cnt++;
}

bool bfs() {
for(int i = 0;i <= t; i++) {
deep[i] = -1, cur[i] = head[i];
}
queue<int> q;
q.push(s); deep[s] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(deep[v] == -1 && e[i].cap) {
deep[v] = deep[u] + 1;
q.push(v);
}
}
}
if(deep[t] >= 0) return true;
else return false;
}

int dfs(int u, int mx) {
int a;
if(u == t) return mx;
for(int i = cur[u]; ~i; i = e[i].next) {
cur[u] = i;
int v = e[i].v;
if(e[i].cap && deep[v] == deep[u] + 1 && (a = dfs(v, min(mx, e[i].cap)))) {
e[i].cap -= a;
e[i ^ 1].cap += a;
return a;
}
}
return 0;
}

void dinic() {
while(bfs()) {
while(1) {
int res = dfs(s, INF);
if(!res) break;
maxflow += res;
}
}
}
}mf;

void solve() {
int n, q; cin >> n >> q;
mf.init();
int ans = 0;
mf.n = n; mf.s = 0; mf.t = n + 1;
vector<int> w(n + 1), m(n + 1);
for(int i = 1;i <= n; i++) cin >> w[i], ans += w[i];
for(int i = 1;i <= q; i++) {
int x, y, v0, v1, v2; cin >> x >> y >> v0 >> v1 >> v2;
ans += v0 + v1;
w[x] += v0 / 2; w[y] += v0 / 2;
m[x] += v1 / 2; m[y] += v1 / 2;
mf.add(x, y, v2 + (v0 + v1) / 2);
mf.add(y, x, v2 + (v0 + v1) / 2);
}
for(int i = 1;i <= n; i++) {
mf.add(mf.s, i, m[i]);
mf.add(i, mf.t, w[i]);
}
mf.dinic();
cout << ans - mf.maxflow << endl;
}

signed main() {
solve();
}

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2021/03/27/nowcoder-practice40-f/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!