[WC2016]挑战NPC

题目传送门

分析:
先使用人类智慧进行构造
每个筐拆成三个点,相互连边
每个球向它可以放的筐拆成的三个点连边
如果一个筐半空,那么拆成的三个点会有两个以上没有和球匹配
那么它们自身能构成一个匹配
每个球都能放进去,求一下原图的最大匹配
答案就是最大匹配-球数
(又一次被开除人籍

一般图的最大匹配使用带花树,大致原理是将奇环缩点找增广路
可以看看网上的讲解

#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\n",ans-n);
		for(int i=1;i<=n;i++)printf("%d ",(match[3*m+i]+2)/3);
	}
}

posted @ 2020-06-10 22:14  Izayoi_Doyo  阅读(259)  评论(0编辑  收藏  举报