首页 > 代码库 > BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

题目大意:给定n个男生和n个女生,一些互相喜欢而一些不,举行几次舞会,每次舞会要配成n对,不能有相同的组合出现,每个人只能与不喜欢的人跳k次舞,求最多举行几次舞会

将一个人拆成两个点,点1向点2连一条流量为k的边,两个人若互相喜欢则点1之间连边,不喜欢则点2之间连边

对于每一个要验证的x值 将每个人的点1向源或汇连一条流量为x的边

然后二分答案跑最大流即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 220
#define INF 0x3f3f3f3f
#define S 0
#define T (n<<2|1)
using namespace std;
struct abcd{
	int to,f,next;
}table[100100];
int head[M],tot=1;
int n,k;
char s[M];
int dpt[M];
bool BFS()
{
	static int q[M],r,h;
	int i;
	memset(dpt,-1,sizeof dpt);
	r=h=0;q[++r]=S;dpt[S]=1;
	while(r!=h)
	{
		int x=q[++h];
		for(i=head[x];i;i=table[i].next)
			if(table[i].f&&!~dpt[table[i].to])
			{
				dpt[table[i].to]=dpt[x]+1;
				q[++r]=table[i].to;
				if(table[i].to==T)
					return true;
			}
	}
	return false;
}
int Dinic(int x,int flow)
{
	int i,left=flow;
	if(x==T) return flow;
	for(i=head[x];i&&left;i=table[i].next)
		if(table[i].f&&dpt[table[i].to]==dpt[x]+1)
		{
			int temp=Dinic(table[i].to, min(left,table[i].f) );
			if(!temp) dpt[table[i].to]=-1;
			left-=temp;
			table[i].f-=temp;
			table[i^1].f+=temp;
		}
	return flow-left;
}
inline void Add(int x,int y,int z)
{
	table[++tot].to=y;
	table[tot].f=z;
	table[tot].next=head[x];
	head[x]=tot;
}
inline void Link(int x,int y,int z)
{
	Add(x,y,z);
	Add(y,x,0);
}
inline void Restore()
{
	int i;
	for(i=2;i<=tot;i+=2)
		table[i].f+=table[i^1].f,table[i^1].f=0;
}
bool Judge(int x)
{
	int i;
	Restore();
	for(i=tot-(n<<2)+1;i<=tot;i+=2)
		table[i].f=x;
	int ans=0;
	while( BFS() )
		ans+=Dinic(S,INF);
	return ans==n*x;
}
int Bisection()
{
	int l=0,r=n;
	while(l+1<r)
	{
		int mid=l+r>>1;
		if( Judge(mid) )
			l=mid;
		else
			r=mid;
	}
	if( Judge(r) )
		return r;
	return l;
}
int main()
{
	int i,j;
	cin>>n>>k;
	for(i=1;i<=n;i++)
	{
		Link(i,n+i,k);
		Link(n+n+i,n+n+n+i,k);
	}
	for(i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(j=1;j<=n;j++)
		{
			if(s[j]=='Y')
				Link(i,n+n+n+j,1);
			else
				Link(n+i,n+n+j,1);
		}
	}
	for(i=1;i<=n;i++)
	{
		Link(S,i,0);
		Link(n+n+n+i,T,0);
	}
	cout<<Bisection()<<endl;
}
//0 源点
//1~n 男性第一个点
//n+1~2n 男性第二个点
//2n+1~3n 女性第二个点
//3n+1~4n 女性第一个点
//4n+1 汇点



BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流