Orz vfk
前一段写过一次带花树,现在已经不会敲板子了。。
把每个筐拆成一个三角形,每个球向匹配的筐的三个点连边,然后跑带花树。答案是匹配数-n,因为每个半空的筐都会自己得到一个匹配,而且一定存在一种最大匹配使所有球匹配。
感觉这种题即使考场上想出来了板子能不能敲对还是个问题(汗)。。。
#include <bits/stdc++.h>
using namespace std;
#define N 1100
#define M 210000
int T,n,m,e,tot,cnt,tail,ans,tim;
int num[N][3],head[N],nex[M],to[M],fa[N];
int match[N],q[N],vis[N],lin[N],type[N];
void init()
{
tot=0;ans=0;
memset(head,0,sizeof(head));
memset(match,0,sizeof(match));
memset(lin,0,sizeof(lin));
}
void add(int x,int y)
{
tot++;
nex[tot]=head[x];head[x]=tot;
to[tot]=y;
}
void ade(int x,int y)
{add(x,y);add(y,x);}
int get_lca(int x,int y)
{
for(tim++;;swap(x,y))
if(x)
{
if(vis[x]==tim)return x;
vis[x]=tim;x=fa[lin[match[x]]];
}
}
void update(int x,int y,int lca)
{
while(fa[x]!=lca)
{
lin[x]=y;
fa[x]=fa[match[x]]=lca;
type[q[++tail]=match[x]]=0;
x=lin[y=match[x]];
}
}
int bfs(int x)
{
memset(type,-1,sizeof(type));
for(int i=1;i<=n;i++)fa[i]=i;
q[tail=1]=x;type[x]=0;
for(int i=1,u,v;i<=tail;i++)
{
for(int j=head[u=q[i]];j;j=nex[j])
{
if(type[v=to[j]]==-1)
{
type[v]=1;lin[v]=u;
int nv=match[v];
if(!nv)
{
while(v)
{
nv=match[lin[v]];
match[match[v]=lin[v]]=v;
v=nv;
}
return 1;
}
type[q[++tail]=nv]=0;
}
else if(type[v]==0&&fa[u]!=fa[v])
{
int lca=get_lca(u,v);
update(u,v,lca);update(v,u,lca);
for(int k=1;k<=n;k++)fa[k]=fa[fa[k]];
}
}
}
return 0;
}
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d",&T);
for(;T--;)
{
init();
scanf("%d%d%d",&n,&m,&e);
cnt=n;
for(int i=1;i<=m;i++)
{
for(int j=0;j<3;j++)num[i][j]=++cnt;
for(int j=0;j<3;j++)
ade(num[i][j],num[i][(j+1)%3]);
}
for(int i=1,x,y;i<=e;i++)
{
scanf("%d%d",&x,&y);
for(int j=0;j<3;j++)
ade(x,num[y][j]);
}
int n1=n;n=cnt;
for(int i=1;i<=n;i++)
if(!match[i]&&bfs(i))ans++;
printf("%d\n",ans-n1);
}
return 0;
}