zoukankan      html  css  js  c++  java
  • BZOJ 1305:dance跳舞(二分+最大流)

    一次舞会有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

    思路:二分答案,然后最大流。

    建图:对于每个男生,拆成两个点A,B(而且A给B分流,流量为K):A用来连接喜欢的女生,B用来连接不喜欢的女生。很明显,二分到num时,给个A拥有num的流量,B拥有K流量。

    同理:女生那里也要拆点。并且,男生流出的流和女生进入的流都要加num的限制。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int inf=10000000;
    const int maxn=40010;
    char mp[60][60];
    int Laxt[maxn],Next[maxn],To[maxn],cap[maxn],cnt;
    int dis[maxn],vd[maxn],S,N,T,K;
    void add(int u,int v,int val)
    {
        Next[++cnt]=Laxt[u];
        Laxt[u]=cnt;
        To[cnt]=v;
        cap[cnt]=val;
    }
    int sap(int u,int flow)
    {
        if(flow==0||u==T) return flow;
        int tmp,delta=0;
        for(int i=Laxt[u];i;i=Next[i]){
            if(dis[u]==dis[To[i]]+1&&cap[i]>0){
               tmp=sap(To[i],min(cap[i],flow-delta));
                delta+=tmp;
               cap[i]-=tmp;
               cap[i^1]+=tmp;
               if(delta==flow||dis[S]>T+1) return delta; 
            }
        }
        vd[dis[u]]--;
        if(vd[dis[u]]==0) dis[S]=T+2;
        vd[++dis[u]]++;
        return delta;
    }
    bool check(int num)
    {
        int res=0; cnt=1;
        for(int i=S;i<=T;i++) Laxt[i]=dis[i]=vd[i]=0;
        for(int i=1;i<=N;i++) { add(S,i,num); add(i,S,0); } //分散给男生 
        for(int i=1;i<=N;i++) { add(i,N+i,K); add(N+i,i,0); } //给不喜欢的分配名额 
        for(int i=1;i<=N;i++)
         for(int j=1;j<=N;j++)
           if(mp[i][j]=='Y'){ add(i,3*N+j,1);add(3*N+j,i,0); } //给喜欢的女生分配 
           else { add(N+i,2*N+j,1); add(2*N+j,N+i,0);  }//给不喜欢的分配 
        for(int i=2*N+1;i<=2*N+N;i++){ add(i,N+i,K); add(T,i,0); } //汇聚到女生 
        for(int i=3*N+1;i<=3*N+N;i++){ add(i,T,num); add(T,i,0); } //汇聚到汇点 
        while(dis[S]<=T+1) res+=sap(S,inf);
        if(res==num*N) return true;
        return false;
    }
    int main()
    {
        scanf("%d%d",&N,&K); S=0; T=4*N+1;
        for(int i=1;i<=N;i++) scanf("%s",mp[i]+1);
        int L=0,R=N,Mid,ans=0;
        while(L<=R){
            Mid=(L+R)>>1;
            if(check(Mid)) ans=Mid,L=Mid+1;
            else R=Mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    CentOS配置sshd
    求逆元 HDU 2516
    求逆元
    二分图的最大匹配
    博弈1
    几何多边形面积交模板
    LAMP服务器的搭建
    扩展欧几里得
    cf780c
    利用栈的逆波兰表达式
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8652969.html
Copyright © 2011-2022 走看看