bzoj1305: [CQOI2009]dance跳舞

传送门
拆点网络流+二分答案。
将每一个人拆成ix和iy
如果男女互相喜欢,则在x节点之间加边。
否则在y节点之间加边。(边权为1)
然后男生从x连向y,女生从y连向x,连流量为k的边。
从原点向男生的x节点连流量为a的边。
从女生的x节点向汇点连流量为a的边。
然后二分答案a,判断是否满足n*a==maxflow即可。

#include<cstring>  
#include<cmath>   
#include<cstdio>  
#include<iostream>  
#include<cstdlib>   
#include<algorithm>
#define inf 2100000000
using namespace std;
struct edge{
    int from,to,next,u;
}e[10005];
char a[55][55];
int head[205],q[10005],dis[205],from[205];
int n,k,l,r,m,S,T,s,ans,tot;
inline int add(int x,int y,int u){
    tot++;
    e[tot].from=x;
    e[tot].to=y;
    e[tot].u=u;
    e[tot].next=head[x];
    head[x]=tot;
}
inline int ins(int x,int y,int u){
    add(x,y,u);
    add(y,x,0);
}
inline void build(int x){
    tot=1;
    memset(head,0,sizeof(head));
    for (int i=1;i<=n;i++) ins(S,i,x);
    for (int i=1;i<=n;i++) ins(i+2*n,T,x);
    for (int i=1;i<=n;i++) ins(i,i+n,k);
    for (int i=1;i<=n;i++) ins(i+3*n,i+2*n,k);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if (a[i][j]=='Y') ins(i,j+2*n,1);
            else ins(i+n,j+3*n,1);
}
inline int spfa(){
    for (int i=1;i<=4*n+2;i++) dis[i]=inf;
    dis[4*n+1]=0;
    int h=0,t=1,x;
    q[1]=4*n+1;
    while (h<t){
        h++;
        x=q[h];
        for (int i=head[x];i;i=e[i].next)
            if (dis[e[i].to]==inf&&e[i].u!=0){
                dis[e[i].to]=dis[x]+1;
                from[e[i].to]=i;
                q[++t]=e[i].to;
            }
    }
    if (dis[4*n+2]!=inf) return 1;
    return 0;
}
inline void del(){
    int x=inf;
    s++;
    for (int i=T;i!=S;i=e[from[i]].from){
        e[from[i]].u--;
        e[from[i]^1].u++;
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%s",a[i]+1);
    l=0; r=50; S=n*4+1; T=S+1;
    while (l<=r){
        m=(l+r)/2;
        build(m);
        s=0;
        while (spfa()) del();
        if (s==m*n){ans=m; l=m+1;}
            else r=m-1;
    }
    printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值