将每个框拆成三个点。
球向三个点连边,框内连两个边(都连和连两个效果是一样的)。
若拆点后有两点连了则说明小于等于1,贡献为1,减去每个球的贡献就是答案。
#include<bits/stdc++.h>
using namespace std;
int n, m, tl, hed[5005], mp[5005], cnt, f[5005], jb[5005], pre[5005], ttt, ee;
int inx, vis[5005];
struct node {
int v, nxt;
}e[500005];
void add(int u, int v) {
e[++tl].v = v;
e[tl].nxt = hed[u];
hed[u] = tl;
}
int fth(int x) {
return f[x] == x ? x : f[x] = fth(f[x]);
}
queue<int>que;
int lca(int x, int y) {
++inx;
for(;;swap(x, y)) {
if(!x) continue;
x = fth(x);
if(vis[x] == inx) return x;
vis[x] = inx;
x = pre[mp[x]];
}
}
void unit(int u, int v, int t) {
int z;
while(fth(u) != t) {
pre[u] = v;
z = mp[u];
if(jb[z] == 2) {
jb[z] = 1;
que.push(z);
}
if(fth(u) == u) f[u] = t;
if(fth(z) == z) f[z] = t;
v = z;
u = pre[v];
}
}
bool find(int s) {
int i, j;
for(i = 1; i <= m * 3 + n; ++i) {
f[i] = i;
jb[i] = -1;
}
while(!que.empty()) que.pop();
que.push(s);
jb[s] = 1;
int u, v, x1, x2, t, las, now;
while(!que.empty()) {
u = que.front();
que.pop();
for(i = hed[u]; ~i; i = e[i].nxt) {
v = e[i].v;
if(jb[v] < 0) {
jb[v] = 2;
pre[v] = u;
if(!mp[v]) {
now = v;
for(; now; now = las) {
las = mp[t = pre[now]];
mp[now] = t;
mp[t] = now;
}
return 1;
}
else {
jb[mp[v]] = 1;
que.push(mp[v]);
}
}
else if(jb[v] == 1 && fth(u) != fth(v)){
t = lca(u, v);
unit(u, v, t);
unit(v, u, t);
}
}
}
return 0;
}
int main() {
cin >> ttt;
int i, u, v;
while(ttt--) {
cin >> n >> m >> ee;
tl = 0; cnt = 0; inx = 0;
memset(hed, -1, sizeof(hed));
memset(mp, 0, sizeof(mp));
memset(pre, 0, sizeof(pre));
memset(vis, 0, sizeof(vis));
for(i = 1; i <= ee; ++i) {
cin >> u >> v;
add(3 * m + u, 3 * (v - 1) + 1);
add(3 * (v - 1) + 1, 3 * m + u);
add(3 * m + u, 3 * (v - 1) + 2);
add(3 * (v - 1) + 2, 3 * m + u);
add(3 * m + u, 3 * (v - 1) + 3);
add(3 * (v - 1) + 3, 3 * m + u);
}
for(i = 1; i <= m; ++i) {
add(3 * (i - 1) + 1, 3 * (i - 1) + 2);
add(3 * (i - 1) + 2, 3 * (i - 1) + 1);
}
for(i = 3 * m + 1; i <= 3 * m + n; ++i) {
if(mp[i]) continue;
if(find(i))++cnt;
}
for(i = 1; i <= 3 * m; ++i ) {
if(mp[i]) continue;
if(find(i))++cnt;
}
cout << cnt - n << endl;
// for(i = 1; i <= 3 * m + n; ++i ) cout << mp[i] << " "; cout << endl;
// for(i = 1; i <= n; ++i) cout << (mp[m * 3 + i] - 1) / 3 + 1 << " ";
// cout << endl;
}
return 0;
}