题目传送门
分析: 先使用人类智慧进行构造 每个筐拆成三个点,相互连边 每个球向它可以放的筐拆成的三个点连边 如果一个筐半空,那么拆成的三个点会有两个以上没有和球匹配 那么它们自身能构成一个匹配 每个球都能放进去,求一下原图的最大匹配 答案就是最大匹配-球数 (又一次被开除人籍
一般图的最大匹配使用带花树,大致原理是将奇环缩点找增广路 可以看看网上的讲解
#include #include #include #include #include #include #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; queueQ; 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\n",ans-n); for(int i=1;i<=n;i++)printf("%d ",(match[3*m+i]+2)/3); } }