EK算法:参考博客
这题建图很巧,具体怎么建图是看的这篇博客:最大流+匹配+拆点
由于我是用邻接表建图的,每次找到增广路要回溯更新,不仅要记录增广路的前驱结点,由于邻接表的特殊性还要记录前驱结点的edge下标,这样才有办法更新。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
const int mx = 100005;
const int inf = 0x3f3f3f3f;
int N, F, D, st, ed, tot;
int head[mx], pre[mx], flow[mx], pe[mx];
queue <int> Q;
struct node {
int v, next, cap;
}edge[mx];
void add(int u, int v) {
edge[tot].v = v;
edge[tot].next = head[u];
edge[tot].cap = 1;
head[u] = tot++;
edge[tot].v = u;
edge[tot].next = head[v];
edge[tot].cap = 0;
head[v] = tot++;
}
int bfs() {
memset(pre, -1, sizeof(pre));
while (!Q.empty()) Q.pop();
Q.push(st);
flow[st] = inf;
while (!Q.empty()) {
int now = Q.front();
Q.pop();
if (now == ed) break;
for (int i = head[now]; i != -1; i = edge[i].next) {
int next = edge[i].v;
if (pre[next] == -1 && edge[i].cap > 0) {
pre[next] = now;
pe[next] = i;//记录edge下标
flow[next] = min(flow[now], edge[i].cap);
Q.push(next);
}
}
}
return pre[ed]==-1?-1:flow[ed];
}
int solve() {
int max_flow = 0, step = -1;
flow[st] = inf;
while ((step = bfs()) != -1) {
max_flow += step;
for (int i = ed; i != st; i = pre[i]) {
edge[pe[i]].cap -= step;
edge[pe[i]^1].cap += step;
}
}
return max_flow;
}
void init() {
memset(head, -1, sizeof(head));
memset(pre, -1, sizeof(pre));
st = tot = 0;
}
int main() {
while (scanf("%d%d%d", &N, &F, &D) != EOF) {
init();
st = 0; ed = 2*N+F+D+1;
for (int i = 1; i <= F; i++) add(0,i);
for (int i = 1; i <= D; i++) add(F+2*N+i,ed);
for (int i = 1; i <= N; i++) add(F+i, F+N+i);
for (int i = 1; i <= N; i++) {
int x, y, tmp;
scanf("%d%d", &x, &y);
for (int j = 1; j <= x; j++) {
scanf("%d", &tmp);
add(tmp, F+i);
}
for (int j = 1; j <= y;j++) {
scanf("%d", &tmp);
add(F+N+i,F+2*N+tmp);
}
}
printf("%d\n", solve());
}
return 0;
}