dance party
Time Limit: 2 Sec Memory Limit: 128 MBSubmissions: 374 Solved: 136
Description
You are organizing a dance party. The party will be attended by n boys and n girls. There will be several rounds of dancing.
In each round, you divide the guests into n dancing pairs. Each guest must be in exactly one pair, and each pair must contain one boy and one girl. Each boy must dance with a different girl in every round. Some boys and girls like each other and some do not. During the party, each boy agrees to dance with at most k girls he doesn't like. Similarly, each girl agrees to dance with at most k boys she doesn't like.
You are given the each pairs of boys and girls who agree to dance with each other .Find out the maximum number of rounds you can organize.
Input
The first line contains a integer t,which means there are t cases followed.
For each case,the first line contain three integer n,m,k ,which means there are n boys and n girls attending the party and m pairs of boys and girls who agree to dance with each other,and each boy or girl agrees to dance with at most k girls or boys he or she doesn't like.At last ,there are m lines with two integers a,b which means boy a and girl b agree to dance with each other.
(0<n<=100,0<m<=n*n,0<k<100,0<a,b<=n)
Output
The output cotains only one integer which means the maximum number of rounds you can organize.
Sample Input
2 2 4 0 1 1 2 2 2 1 1 2 3 7 0 1 1 1 2 1 3 2 1 2 2 3 1 3 3
Sample Output
2 2
HINT
Source
lshmouse
分析:这题可以看成求最多次能做几次二分图完全匹配,即最大流刚好为点的倍数,于是可以二分答案,然后用最大流判断是否可行,关键在于构图:
二分答案ans;
将每个男孩看成左边的点X,女孩为右边的点Y,然后将X分为与自己喜欢的跳舞Xa,不喜欢的Xb,Y同分为Ya,Yb,在源点src与所以Xa之间连一条容量为ans的有向边,在Ya与汇点dest之间连一条容量为ans的有向边,在Xa与Xb,Yb与Ya之间连一条有向边,之后在枚举所以男孩i,女孩j,如果i可以和j一起,则在Xai与Yaj之间连一条容量为1的有向边,否则在Xbi与Ybj之间连一条有向边,当前最大流如果为n的倍数及答案ans可行。。。
代码:
#include<cstdio>
using namespace std;
const int mm=111111;
const int mn=444;
const int oo=1000000000;
int node,src,dest,edge,k,n;
int reach[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
bool like[111][111];
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0; i<node; ++i)head[i]=-1;
edge=0;
}
inline void addedge(int u,int v,int c)
{
reach[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
reach[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
}
bool Dinic_bfs()
{
int i,u,v,l,r=0;
for(i=0; i<node; ++i)dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0; l<r; ++l)
for(i=head[u=q[l]]; i>=0; i=next[i])
if(flow[i]&&dis[v=reach[i]]<0)
{
dis[q[r++]=v]=dis[u]+1;
if(v==dest)return 1;
}
return 0;
}
int Dinic_dfs(int u,int exp)
{
if(u==dest)return exp;
for(int &i=work[u],v,tmp; i>=0; i=next[i])
if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}
return 0;
}
int Dinic_flow()
{
int i,ret=0,delta;
while(Dinic_bfs())
{
for(i=0; i<node; ++i)work[i]=head[i];
while(delta=Dinic_dfs(src,oo))ret+=delta;
}
return ret;
}
inline void fresh(int c)
{
int i,j;
for(i=0; i<edge; ++i)flow[i]=((i&1)==0);
for(i=1; i<=n; ++i)
{
flow[head[i]^1]=c;
flow[head[i+3*n]]=c;
flow[head[i+2*n]]=k;
flow[next[head[i]]]=k;
}
}
int main()
{
int i,j,m,t,l,r;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j)like[i][j]=0;
while(m--)scanf("%d%d",&i,&j),like[i][j]=1;
prepare(n*4+2,0,n*4+1);
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j)
if(like[i][j])addedge(i,j+3*n,0);
else addedge(i+n,j+2*n,0);
for(i=1; i<=n; ++i)
{
addedge(i,i+n,0);
addedge(i+2*n,i+3*n,0);
addedge(src,i,0);
addedge(i+3*n,dest,0);
}
l=0,r=n;
while(l<=r)
{
m=(l+r)>>1;
fresh(m);
if(Dinic_flow()==n*m)l=m+1;
else r=m-1;
}
printf("%d\n",l-1);
}
return 0;
}