戳戳看题
这道题的核心就是教你建双向边。我们发现本题的权值是在点上的。那么我们可以将1个点拆成2个点(一个点是入,一个点是出),中间的权值为val[i]。
上马!
#include<cstdio>
#include<cctype>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 90002, lim = (1 << 30) - 1;
int val[N], s, t, d[N], cur[N], n, m, cnt, nxt[N], flow[N], to[N], head[N];
inline int read() {
int x = 0, f = 1;
char s = getchar();
while(! isdigit(s)) {
if(s == '-')
f = -1;
s = getchar();
}
while(isdigit(s)) {
x = (x << 1) + (x << 3) + (s ^ 48);
s = getchar();
}
return x * f;
}
inline void print(int x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
void addEdge(const int u, const int v, const int w) {
to[++ cnt] = v;
nxt[cnt] = head[u];
flow[cnt] = w;
head[u] = cnt;
}
int dfs(const int u, const int Flow) {
if(u == t)
return Flow;
for(int &i = cur[u]; ~i; i = nxt[i]) {
int v = to[i];
if(d[v] == d[u] + 1 && flow[i] > 0) {
int dis = dfs(v, min(Flow, flow[i]));
if(dis > 0) {
flow[i] -= dis;
flow[i ^ 1] += dis;
return dis;
}
}
}
return 0;
}
bool bfs() {
queue <int> q;
while(! q.empty())
q.pop();
memset(d, 0, sizeof d);
d[s] = 1;
q.push(s);
while(! q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = nxt[i]) {
int v = to[i];
if(d[v] == 0 && flow[i] > 0) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d[t] > 0;
}
int dinic() {
int ans = 0, dis;
while(bfs()) {
for(int i = 1; i <= (n << 1); ++ i)
cur[i] = head[i];
while(dis = dfs(s, lim))
ans += dis;
}
return ans;
}
int main() {
int a, b;
while(scanf("%d", &n) != EOF) {
m = read();
s = read();
t = read() + n;
cnt = -1;
memset(head, -1, sizeof head);
for(int i = 1; i <= n; ++ i) {
val[i] = read();
addEdge(i, i + n, val[i]);
addEdge(i + n, i, 0);
}
for(int i = 1; i <= m; ++ i) {
a = read();
b = read();
addEdge(b + n, a, lim);
addEdge(a, b + n, 0);
addEdge(a + n, b, lim);
addEdge(b, a + n, 0);
}
printf("%d\n", dinic());
}
return 0;
}
来源:CSDN
作者:我只是想康康昵称会显示在哪里
链接:https://blog.csdn.net/LBCLZMB/article/details/103481249