P3153 [CQOI2009]跳舞

P3153 [CQOI2009]跳舞

考虑建模

将男生和女生分别拆成两个点 (喜欢、不喜欢)

二分容量,跑满了则增大

(S)向男生喜欢连(mid)容量,男生喜欢向男生不喜欢连(k)容量

女生拆成的点同理

按矩阵,喜欢向喜欢,不喜欢向不喜欢连容量为(1)的边

My complete

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
typedef long long LL;
const LL maxn=50000;
const LL inf=0x3f3f3f3f;
inline LL Read(){
    LL x=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<3)+(x<<1)+c-'0'; c=getchar();
    }return x*f;
}
struct node{
    LL to,next,flow;
}dis[maxn];
LL n,K,num,S,T,ans;
LL head[maxn],dep[maxn];
char s[100][100];
inline void Add(LL u,LL v,LL flow){
    dis[++num]=(node){v,head[u],flow}; head[u]=num;
}
inline LL Bfs(){
    queue<LL> que;
    que.push(S);
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    while(que.size()){
        LL u=que.front(); que.pop();
        for(LL i=head[u];i!=-1;i=dis[i].next){
            LL v=dis[i].to;
            if(!dep[v]&&dis[i].flow){
                dep[v]=dep[u]+1;
                que.push(v);
            }
        }
    }
    return dep[T];
}
LL Dinic(LL u,LL flow){
    if(u==T)
        return flow;
    LL tmp=flow;
    for(LL i=head[u];i!=-1;i=dis[i].next){
        LL v=dis[i].to;
        if(tmp&&dis[i].flow&&dep[v]==dep[u]+1){
            LL now=Dinic(v,min(tmp,dis[i].flow));
            if(now){
                dis[i].flow-=now;
                dis[i^1].flow+=now;
                tmp-=now;
            }else
                dep[v]=inf;
        }
    }
    return flow-tmp;
}
inline LL Solve(){
    LL sum=0;
    while(Bfs())
        sum+=Dinic(S,inf);
    return sum;
}
inline bool Check(LL mid){
    S=0; T=4*n+1;
    memset(head,-1,sizeof(head));
    num=-1;
    for(LL i=1;i<=n;++i){
        Add(S,i,mid),Add(i,S,0);
        Add(i+2*n,T,mid),Add(T,i+2*n,0);
        Add(i,i+n,K),Add(i+n,i,0);
        Add(i+3*n,i+2*n,K),Add(i+2*n,i+3*n,0);
    }
    for(LL i=1;i<=n;++i){
        for(LL j=1;j<=n;++j){
            if(s[i][j]=='Y'){
                Add(i,j+2*n,1),Add(j+2*n,i,0);
            }else{
                Add(i+n,j+3*n,1),Add(j+3*n,i+n,0);
            }
        }
    }
    if(Solve()==n*mid)
        return true;
    return false;
}
int main(){
    n=Read(),K=Read();
    for(LL i=1;i<=n;++i)
        scanf(" %s",s[i]+1);
    LL l=0,r=n;
    while(l<=r){
        LL mid=(l+r)>>1;
        if(Check(mid)){
            ans=mid;
            l=mid+1;
        }else
            r=mid-1;
    }
    printf("%lld",ans);
}/*
3 0
YYY
YYY
YYY

3
*/
原文地址:https://www.cnblogs.com/y2823774827y/p/10149118.html