hust 1024(二分+最大流)

dance party

Time Limit: 2 Sec   Memory Limit: 128 MB
Submissions: 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值