BZOJ1305: [CQOI2009]dance跳舞

Description

一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

Input

第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。

Output

仅一个数,即舞曲数目的最大值。

Sample Input

3 0
YYY
YYY
YYY

Sample Output

3

HINT

N<=50 K<=30

Source

拆点+二分
把人拆成两个点 S到男孩 女孩到T连二分的答案
然后男女之间喜欢的连1 不喜欢的连1
最后把拆的点连上K
#include<bits/stdc++.h>
 
using namespace std;
 
const int inf=1e9;
 
int ans;
 
int cnt;
 
int head[1010],q[1010],dis[1010];
 
int n,k,T;
 
struct edge
{
    int to,nxt;
    int flow;
}e[500050];
 
inline void addedge(int x,int y,int fl)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt;
    e[cnt].flow=fl;
    e[++cnt].to=x;
    e[cnt].nxt=head[y];
    head[y]=cnt;
    e[cnt].flow=0;
}
 
bool mp[1010][1010];
 
inline bool bfs()
{
    int ql=0,qr=1;
    q[1]=0;
    memset(dis,0,sizeof(dis));
    dis[0]=1;
    while(ql<qr)
    {
        int x=q[++ql];
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(e[i].flow&&!dis[y])
            {
                dis[y]=dis[x]+1;
                q[++qr]=y;
            }
        }
    }
    if(dis[T]) return true;
    return false;
}
  
inline int dfs(int x,int flow)
{
    if(x==T) return flow;
    int d,used=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(e[i].flow&&dis[y]==dis[x]+1)
        {
            d=dfs(y,min(flow,e[i].flow));
            e[i].flow-=d;
            e[i^1].flow+=d;
            used+=d;
            if(used==flow)
                return flow;
        }
    }
    if(!used)
        dis[x]=-1;
    return used;
}
  
inline void dinic()
{
    while(bfs())
        ans+=dfs(0,inf);
}
 
inline void build(int x)
{
    cnt=1;
    memset(head,0,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        addedge(0,i,x);addedge(i,i+500,k);
        addedge(i+n+500,i+n,k);addedge(i+n,T,x);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(mp[i][j]) addedge(i,n+j,1);
            else addedge(i+500,n+j+500,1);
}
 
int main()
{
    scanf("%d%d",&n,&k);
    T=1001;
    for(int i=1;i<=n;i++)
    {
        char ch[51];
        scanf("%s",ch);
        for(int j=1;j<=n;j++)
            if(ch[j-1]=='Y')
                mp[i][j]=1;
    }
    int mx=0,l=0,r=50;
    while(l<=r)
    {
        int mid=l+r>>1;
        build(mid);
        ans=0;
        dinic();
        if(ans>=n*mid)
            mx=mid,l=mid+1;
        else r=mid-1;
    }
    cout<<mx;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值