题解:
利用奇环的性质来达到二分图中诸如每个点匹配多少个点之后贡献是多少的限制。
因为最大匹配随着点数增加而增加,我们应该想办法使得在特定情况少增加一个。
对于本题每个桶构造一个三角形,每个能放入桶中的球连三个点,发现匹配
0,1
0
,
1
个球时这个三角形和与其相匹配的点减去匹配数等于
2
2
,否则等于,很容易就可以列出计算贡献的式子。
由于新图不是二分图,采用带花树解决最大匹配,时间复杂度
O(n3)
O
(
n
3
)
.
还有一点需要注意的是如果要输出方案的话每个不是桶的点必须有匹配,根据增广路性质不会使得路上的匹配点变为不匹配,因此我们先增广不是桶的点即可。
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=1e3+50;
vector <int> edge[N];
int n,m,nn,id[N],mate[N],pre[N],anc[N];
queue <int> q;
inline void add(int x,int y) {edge[x].push_back(y); edge[y].push_back(x);}
inline int getanc(int x) {return (anc[x]==x)?x:(anc[x]=getanc(anc[x]));}
inline void merge(int x,int y) {anc[getanc(x)]=getanc(y);}
inline int lca(int x,int y) {
static int vis[N],vt; ++vt;
while(x) {
if(vis[x]==vt) return x;
vis[x]=vt; x=getanc(pre[mate[x]]);
if(!x) swap(x,y);
}
}
inline void group(int x,int f) {
while(getanc(x)!=f) {
int y=mate[x], z=pre[y];
if(getanc(z)!=f) pre[z]=y;
if(id[y]) id[y]=0, q.push(y);
if(id[z]) id[z]=0, q.push(z);
merge(x,y); merge(y,z); x=z;
}
}
inline bool bfs(int x) {
for(int i=1;i<=nn;i++) id[i]=-1,anc[i]=i;
while(!q.empty()) q.pop();
pre[x]=0; q.push(x); id[x]=0;
while(!q.empty()) {
int u=q.front(); q.pop();
for(int e=edge[u].size()-1;e>=0;e--) {
int v=edge[u][e];
if(!~id[v]) {
id[v]=1; pre[v]=u;
if(!mate[v]) {
while(u) {
int t=mate[u];
mate[u]=v; mate[v]=u;
v=t; u=pre[v];
}
return true;
}
id[mate[v]]=0; q.push(mate[v]);
} else if(!id[v] && getanc(u)!=getanc(v)) {
int l=lca(getanc(u),getanc(v));
if(getanc(u)!=l) pre[u]=v;
if(getanc(v)!=l) pre[v]=u;
group(u,l); group(v,l);
}
}
}
return false;
}
inline void solve() {
n=rd(), m=rd(); nn=3*m+n; int ans=0;
for(int i=1;i<=nn;i++) edge[i].clear(), mate[i]=0;
for(int i=rd();i;i--) {
int x=rd(), y=rd();
add(x+3*m,y); add(x+3*m,y+m); add(x+3*m,y+2*m);
}
for(int i=1;i<=m;i++) {
add(i,i+m); add(i+m,i+2*m); add(i+2*m,i);
}
for(int i=nn;i;i--) if(!mate[i]) ans+=bfs(i);
printf("%d\n",ans-n);
}
int main() {
for(int T=rd();T;T--) solve();
}