day20T3改错记
题目描述
两个点集\(A\)和\(B\),有\(m\)条边,每条边连接\(A\)中的一个点和\(B\)中的一个点
每个点有属性\(t\)(只能是\(0\)或者\(1\)),若\(a \in A, b \in B, t_a = t_b\),且\(a, b\)之间有边,则\(a\)和\(b\)可以匹配
\(A\)中每个点的\(t\)已知,\(B\)中每个点的\(t\)未知,问在所有可能的情况下,\(A\)和\(B\)的最大匹配的最小是多少
\(|A|, |B| \le 2000, m \le 5000\)
解析
奇妙的网络流建图……
把\(A\)中的点分为\(t\)为\(0\)和\(t\)为\(1\)分成两部分\(A_0, A_1\),\(S\)向\(A_0\)中每个点连容量为\(1\)的边,\(A_1\)中每个点向\(T\)连容量为\(1\)的边
把\(B\)中每个点拆成\(b_0, b_1\)两个点,\(b_0\)向\(b_1\)连一条容量为\(1\)的边
\(A_0\)中每个点向能匹配的\(b_0\)连容量\(inf\)的边,每个\(b_1\)向\(A_1\)中能匹配的点连容量\(inf\)的边
跑一遍最小割就是答案
其实依然不太清楚为什么这么连边……
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define MAXN 2005
typedef long long LL;
const int inf = 0x3f3f3f3f;
struct Graph {
struct Edge {
int v, next, cap;
Edge(int _v = 0, int _n = 0, int _c = 0):v(_v), next(_n), cap(_c) {}
} edge[MAXN << 4];
int head[MAXN << 2], cur[MAXN << 2], dep[MAXN << 2], cnt;
void init() { memset(head, -1, sizeof head); cnt = 0; }
void add_edge(int u, int v, int c) { edge[cnt] = Edge(v, head[u], c); head[u] = cnt++; }
void insert(int u, int v, int c) { add_edge(u, v, c); add_edge(v, u, 0); }
bool bfs();
int dfs(int, int);
int dinic();
};
char gc();
int read();
int N, M, K, t[MAXN];
Graph G;
int main() {
freopen("deadline.in", "r", stdin);
freopen("deadline.out", "w", stdout);
N = read(), M = read(), K = read();
G.init();
for (int i = 1; i <= N; ++i) {
t[i] = read();
if (t[i]) G.insert(i, N + (M << 1) + 1, 1);
else G.insert(0, i, 1);
}
while (K--) {
int x = read(), y = read();
if (t[x]) G.insert(N + M + y, x, inf);
else G.insert(x, N + y, inf);
}
for (int i = 1; i <= M; ++i) G.insert(N + i, N + M + i, 1);
printf("%d\n", G.dinic());
return 0;
}
inline char gc() {
static char buf[1000000], *p1, *p2;
if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
return p1 == p2 ? EOF : *p2++;
}
inline int read() {
int res = 0; char ch = gc();
while (ch < '0' || ch > '9') ch = gc();
while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
return res;
}
bool Graph::bfs() {
memset(dep, 0, sizeof dep);
int que[MAXN << 2], hd = 0, tl = 0;
que[tl++] = 0, dep[0] = 1;
while (hd < tl) {
int p = que[hd++];
if (p == N + (M << 1) + 1) return 1;
for (int i = head[p]; ~i; i = edge[i].next)
if (edge[i].cap && !dep[edge[i].v]) {
dep[edge[i].v] = dep[p] + 1;
que[tl++] = edge[i].v;
}
}
return 0;
}
int Graph::dfs(int u, int max_flow) {
if (u == N + (M << 1) + 1) return max_flow;
int res = 0;
for (int &i = cur[u]; ~i; i = edge[i].next)
if (edge[i].cap && dep[edge[i].v] == dep[u] + 1) {
int d = dfs(edge[i].v, std::min(max_flow, edge[i].cap));
if (d) {
res += d, max_flow -= d;
edge[i].cap -= d, edge[i ^ 1].cap += d;
if (!max_flow) break;
}
}
if (!res) dep[u] = -1;
return res;
}
int Graph::dinic() {
int res = 0;
while (bfs()) {
memcpy(cur, head, sizeof head);
res += dfs(0, inf);
}
return res;
}
//Rhein_E 100pts