Sol
这做法我是想不到\(TAT\)
每个筐子拆成三个相互连边
球向三个筐子连边 然后跑一般图最大匹配这三个筐子间最多有一个匹配
那么显然每个球一定会放在一个筐子里,一定有一个匹配 如果筐子间有匹配,则有一个半空的筐子,因为它一定只匹配了小于等于\(1\)个球 答案为匹配数\(-n\) 使答案最大即匹配数最大上带花树就好了
# include# define RG register# define IL inline# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;const int _(1005);const int __(2e5 + 5);typedef int Arr[_];IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}Arr first, match, fa, vis, tim, pre;int n, m, cnt, idx, ans, E, t1, t2, t3;queue Q;struct Edge{ int to, next;} edge[__];IL void Add(RG int u, RG int v){ edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++; edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;}IL int Find(RG int x){ return x == fa[x] ? x : fa[x] = Find(fa[x]);}IL int LCA(RG int x, RG int y){ ++idx, x = Find(x), y = Find(y); while(tim[x] != idx){ tim[x] = idx; x = Find(pre[match[x]]); if(y) swap(x, y); } return x;}IL void Blossom(RG int x, RG int y, RG int p){ while(Find(x) != p){ pre[x] = y, y = match[x]; if(vis[y] == 2) vis[y] = 1, Q.push(y); if(Find(x) == x) fa[x] = p; if(Find(y) == y) fa[y] = p; x = pre[y]; }}IL int Aug(RG int S){ for(RG int i = 1; i <= t3; ++i) vis[i] = pre[i] = 0, fa[i] = i; while(!Q.empty()) Q.pop(); Q.push(S), vis[S] = 1; while(!Q.empty()){ RG int u = Q.front(); Q.pop(); for(RG int e = first[u]; e != -1; e = edge[e].next){ RG int v = edge[e].to; if(Find(v) == Find(u) || vis[v] == 2) continue; if(!vis[v]){ vis[v] = 2, pre[v] = u; if(!match[v]){ for(RG int x = v, lst; x; x = lst) lst = match[pre[x]], match[pre[x]] = x, match[x] = pre[x]; return 1; } vis[match[v]] = 1, Q.push(match[v]); } else{ RG int p = LCA(u, v); Blossom(u, v, p); Blossom(v, u, p); } } } return 0;}int main(RG int argc, RG char *argv[]){ for(RG int T = Input(); T; --T){ n = Input(), m = Input(), E = Input(); t1 = n + m, t2 = t1 + m, t3 = t2 + m; ans = cnt = idx = 0; for(RG int i = 1; i <= t3; ++i) first[i] = -1, match[i] = 0, tim[i] = 0; for(RG int i = 1; i <= m; ++i) Add(n + i, t1 + i), Add(t1 + i, t2 + i), Add(n + i, t2 + i); for(RG int i = 1, u, v; i <= E; ++i){ u = Input(), v = Input(); Add(u, n + v), Add(u, t1 + v), Add(u, t2 + v); } for(RG int i = 1; i <= t3; ++i) if(!match[i]) ans += Aug(i); printf("%d\n", ans - n); } return 0;}