Orz vfk
将每个框拆成3个点,如果一个球x可以放进一个框y中,就将x和y拆成的3个点连边,每个框拆的3个点互相连边,那么,
当一个框不和任何球匹配时,它贡献的匹配数是1
当一个框和1个球匹配时,它贡献的匹配数是2
当一个框和2个球匹配时,它贡献的匹配数是2
当一个框和3个球匹配时,它贡献的匹配数是3
这样,可得 匹配数-球数=放的球数≤1的框数
因为是无向图,球数不变,所以求无向图最大匹配-球数就是答案
vfk在题解中提到,通过调整建图,≤2,≥1,≥2都是可做的
≤2似乎可以把一个框拆成4个点,球向3个点连边,第4个点向其他三个点连边
其他情况我就不会了,如果有人会,如果能留言告诉我,我将感激不尽
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
char c; int x;
while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9')(x*=10)+=c-'0';
return x;
}
void swap(int &x,int &y){x^=y;y^=x;x^=y;}
const int maxn = 1010;
const int maxm = 331000;
struct edge
{
int y,nex;
edge(){}
edge(const int &_y,const int &_nex){y=_y;nex=_nex;}
}a[maxm]; int len,fir[maxn];
int n,n1,n2,m;
void ins(const int &x,const int &y)
{
a[++len]=edge(y,fir[x]); fir[x]=len;
a[++len]=edge(x,fir[y]); fir[y]=len;
}
int fa[maxn];
int find_(const int &x)
{
if(fa[x]==x) return x;
return fa[x]=find_(fa[x]);
}
void Together(const int &x,const int &y)
{
int f1=find_(x),f2=find_(y);
if(f1!=f2) fa[f1]=f2;
}
int nex[maxn],mark[maxn],spouse[maxn];
int vis[maxn],ti;
int LCA(int x,int y)
{
ti++;
while(true)
{
if(x!=-1)
{
x=find_(x);
if(vis[x]==ti) return x;
vis[x]=ti;
if(spouse[x]!=-1) x=nex[spouse[x]];
else x=-1;
}
swap(x,y);
}
}
int que[maxn],tail;
void group(int x,const int &p)
{
while(x!=p)
{
int b=spouse[x],c=nex[b];
if(find_(c)!=p) nex[c]=b;
if(mark[b]==2) mark[que[++tail]=b]=1;
if(mark[c]==2) mark[que[++tail]=c]=1;
Together(x,b);
Together(b,c);
x=c;
}
}
void augment(const int &s)
{
for(int i=1;i<=n;i++) nex[i]=-1,mark[i]=0,fa[i]=i;
que[tail=1]=s; mark[s]=1;
for(int i=1;i<=tail&&spouse[s]==-1;i++)
{
const int x=que[i];
for(int k=fir[x];k;k=a[k].nex)
{
const int y=a[k].y;
if(find_(x)!=find_(y)&&spouse[x]!=y&&mark[y]!=2)
{
if(spouse[y]==-1)
{
nex[y]=x;
for(int j=y;j!=-1;)
{
int b=nex[j],c=spouse[b];
spouse[b]=j;
spouse[j]=b;
nex[b]=c;
j=c;
}
break;
}
else if(mark[y]==1)
{
const int p=LCA(x,y);
if(find_(x)!=p) nex[x]=y;
if(find_(y)!=p) nex[y]=x;
group(x,p);
group(y,p);
}
else
{
nex[y]=x;
mark[y]=2;
mark[que[++tail]=spouse[y]]=1;
}
}
}
}
}
int main()
{
int t=read();
while(t--)
{
memset(fir,0,sizeof fir); len=0;
memset(vis,0,sizeof vis); ti=0;
n1=read(); n2=read(); m=read();
int N=n2*3;
n=n1+N;
for(int i=1,id=1;i<=n2;i++,id+=3)
{
ins(id,id+1);
ins(id,id+2);
ins(id+1,id+2);
}
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
x+=N; y=(y-1)*3+1;
ins(x,y); ins(x,y+1); ins(x,y+2);
}
memset(spouse,-1,sizeof spouse);
for(int i=n;i>=1;i--)
if(spouse[i]==-1) augment(i);
int re=0;
for(int i=1;i<=n;i++) if(spouse[i]!=-1) re++;
printf("%d\n",(re>>1)-n1);
}
return 0;
}