zoukankan      html  css  js  c++  java
  • bzoj千题计划130:bzoj1305: [CQOI2009]dance跳舞

    http://www.lydsy.com/JudgeOnline/problem.php?id=1305

    每个人拆为喜欢(yes)和不喜欢(no)两个点

    二分答案

    1、每两个人之间只能跳一次

    喜欢则 男yes i 向 女yes j 连流量为1的边

    不喜欢则 男no i 向 女no j 连流量为1的边

    2、最多与k个不喜欢的人跳

    男yes i 向 男no i 连流量为 k的边

    女no j 向 女yes j 连流量为k 的边

    3、

    源点向 男yes i 连流量mid 的边

    女yes j 向汇点连流量为mid的边

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    #define N 2501
    #define M 3001
    
    int n,k;
    char s[51];
    bool mp[51][51];
    
    int tot;
    int front[N],to[M<<1],nxt[M<<1],val[M<<1];
    
    int src,decc;
    
    int cur[N],lev[N];
    
    queue<int>q;
    
    void read(int &x)
    {
        x=0;  char c=getchar();
        while(!isdigit(c)) c=getchar(); 
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=0;
    }
    
    void rebuild(int mid)
    {
        tot=1;
        memset(front,0,sizeof(front));
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(mp[i][j]) add(i,n*3+j,1);
                else add(n+i,n*2+j,1);
        for(int i=1;i<=n;++i) add(src,i,mid);
        for(int i=1;i<=n;++i) add(n*3+i,decc,mid);
        for(int i=1;i<=n;++i) add(i,n+i,k);
        for(int i=1;i<=n;++i) add(n*2+i,n*3+i,k);
    }
    
    bool bfs()
    {
        while(!q.empty()) q.pop();
        for(int i=src;i<=decc;i++) lev[i]=-1,cur[i]=front[i];
        lev[src]=0; 
        q.push(src);
        int now;
        while(!q.empty())
        {
            now=q.front(); q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                if(lev[to[i]]==-1&&val[i]>0)
                {
                    lev[to[i]]=lev[now]+1;
                    if(to[i]==decc) return true;
                    q.push(to[i]);
                }
            }
        }
        return false;
    }
    int dinic(int now,int flow)
    {
        if(now==decc) return flow;
        int rest=0,delta;
        for(int &i=cur[now];i;i=nxt[i])
        {
            if(lev[to[i]]>lev[now]&&val[i]>0)
            {
                delta=dinic(to[i],min(flow-rest,val[i]));
                if(delta)
                {
                    val[i]-=delta; val[i^1]+=delta;
                    rest+=delta; if(rest==flow) break;
                }
            }
        }
        if(rest==flow) lev[now]=-1;
        return rest;
    }
    
    bool check(int mid)
    {
        rebuild(mid);
        int maxflow=0;
        while(bfs()) 
        maxflow+=dinic(src,2e9);
        return maxflow==n*mid;
    }
    
    int main()
    {
        read(n); read(k);
        decc=n*4+1;
        for(int i=1;i<=n;++i)
        {
            scanf("%s",s+1);
            for(int j=1;j<=n;++j) mp[i][j]=s[j]=='Y' ? true : false; 
        }
        int l=0,r=n,mid,ans;
        while(l<=r)
        {
            mid=l+r>>1;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1; 
        }
        cout<<ans;
    }

    1305: [CQOI2009]dance跳舞

    Time Limit: 5 Sec  Memory Limit: 162 MB
    Submit: 3691  Solved: 1565
    [Submit][Status][Discuss]

    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

  • 相关阅读:
    使用git遇到的一些问题
    小程序的生命周期
    git status -s命令解析
    JavaScript 关闭浏览器窗口
    JavaScript 如何编写计算器
    JavaScript 数组对象的去重
    JavaScript 数组排序(从大到小,从小到大)
    JavaScript 常用的Math对象
    JavaScript 获取 当前日期和三十天以前日期
    JavaScript 获取数组的最大值和最小值
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8018489.html
Copyright © 2011-2022 走看看