题目传送门
分析:
先使用人类智慧进行构造
每个筐拆成三个点,相互连边
每个球向它可以放的筐拆成的三个点连边
如果一个筐半空,那么拆成的三个点会有两个以上没有和球匹配
那么它们自身能构成一个匹配
每个球都能放进去,求一下原图的最大匹配
答案就是最大匹配-球数
(又一次被开除人籍
一般图的最大匹配使用带花树,大致原理是将奇环缩点找增广路
可以看看网上的讲解
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<map>
#define maxn 1005
#define maxm 200005
#define INF 0x3f3f3f3f
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,E,N;
int fir[maxn],nxt[maxm],to[maxm],cnt;
int tic[maxn],match[maxn],f[maxn],pre[maxn],tp[maxn],tim;
queue<int>Q;
inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline int find(int x)
{return f[x]==x?x:f[x]=find(f[x]);}
inline int LCA(int x,int y)
{
for(++tim;;swap(x,y))if(x)
{
x=find(x);
if(tic[x]==tim)return x;
else tic[x]=tim,x=pre[match[x]];
}
}
inline void shrink(int x,int y,int p)
{
while(find(x)!=p)
{
pre[x]=y,y=match[x];
if(tp[y]==2)tp[y]=1,Q.push(y);
if(find(x)==x)f[x]=p;
if(find(y)==y)f[y]=p;
x=pre[y];
}
}
inline bool aug(int s)
{
for(int i=1;i<=N;i++)f[i]=i;
while(!Q.empty())Q.pop();
memset(tp,0,sizeof tp),memset(pre,0,sizeof pre);
Q.push(s),tp[s]=1;
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=fir[u];i;i=nxt[i])
{
int v=to[i];
if(find(u)==find(v)||tp[v]==2)continue;
if(!tp[v])
{
tp[v]=2,pre[v]=u;
if(!match[v])
{
for(int now=v,lst;now;now=lst)
{
lst=match[pre[now]];
match[pre[now]]=now,match[now]=pre[now];
}
return 1;
}
tp[match[v]]=1,Q.push(match[v]);
}
else
{
int p=LCA(u,v);
shrink(u,v,p),shrink(v,u,p);
}
}
}
return 0;
}
int main()
{
int T=getint();
while(T--)
{
int ans=0;
memset(fir,0,sizeof fir),cnt=tim=0;
memset(match,0,sizeof match),memset(tic,0,sizeof tic);
n=getint(),m=getint(),E=getint();
while(E--)
{
int u=getint(),v=getint();
newnode(3*v-2,3*m+u),newnode(3*m+u,3*v-2);
newnode(3*v-1,3*m+u),newnode(3*m+u,3*v-1);
newnode(3*v-0,3*m+u),newnode(3*m+u,3*v-0);
}
for(int i=1;i<=m;i++)
{
newnode(3*i-2,3*i-1),newnode(3*i-1,3*i-2);
newnode(3*i-1,3*i-0),newnode(3*i-0,3*i-1);
newnode(3*i-0,3*i-2),newnode(3*i-2,3*i-0);
}
N=3*m+n;
for(int i=N;i;i--)ans+=(!match[i]&&aug(i));
printf("%d
",ans-n);
for(int i=1;i<=n;i++)printf("%d ",(match[3*m+i]+2)/3);
}
}