• 1305. [CQOI2009]跳舞【最大流+二分】


    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

    这个题思路很妙啊……第一次做到在网络流中使用二分的题目
    其实一开始想到用二分限制的,不过并没有深入思考下去
    而是写了一个别人几行就能实现我却用网络流实现的贪心
    正解是拆点加二分。
    因为答案满足单调性,若可以跳x首曲子,则x-1首肯定也是可以的
    建图?
    将每个男生和女生拆成两个点:Yes和No

    超级源点连接男生的Yes,超级汇点连接女生的Yes
    容量设置为二分的x。若跑出来最大流是x*n,就说明满流了
    满流即为可以满足x首曲子

    对于互相喜欢的,我们在男女的两个Yes点间连边
    不喜欢的,我们就在男女的两个No点间连边
    那么如何限制k呢?
    每个男Yes连自己的No,容量为k
    每个女No连自己Yes,容量为k
    这样就可以保证k了

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cmath>
      6 #define MAXM (100000+10)
      7 #define MAXN (10000+10)
      8 using namespace std;
      9 
     10 struct node
     11 {
     12     int Flow;
     13     int next;
     14     int to;
     15 }edge[MAXM*2];
     16 int Depth[MAXN],q[MAXN];
     17 int head[MAXN],num_edge;
     18 int n,m,k,s,e,d,INF;
     19 int a[1010][1010];
     20 char ch[1010];
     21 
     22 void add(int u,int v,int l)
     23 {
     24     edge[++num_edge].to=v;
     25     edge[num_edge].Flow=l;
     26     edge[num_edge].next=head[u];
     27     head[u]=num_edge;
     28 }
     29 
     30 bool Bfs(int s,int e)
     31 {
     32     int Head=0,Tail=1;
     33     memset(Depth,0,sizeof(Depth));
     34     Depth[s]=1;
     35     q[1]=s;
     36     while (Head<Tail)
     37     {
     38         ++Head;
     39         int x=q[Head];
     40         for (int i=head[x];i!=0;i=edge[i].next)
     41             if (!Depth[edge[i].to] && edge[i].Flow>0)
     42             {
     43                 Depth[edge[i].to]=Depth[x]+1;
     44                 q[++Tail]=edge[i].to;
     45             }
     46     }
     47     if (Depth[e]>0) return true;
     48     return false;
     49 }
     50 
     51 int Dfs(int x,int low)
     52 {
     53     int Min,f=0;
     54     if (x==e || low==0)
     55         return low;
     56     for (int i=head[x];i!=0;i=edge[i].next)
     57         if (edge[i].Flow>0 && Depth[edge[i].to]==Depth[x]+1 && (Min=Dfs(edge[i].to , min(low,edge[i].Flow) )))
     58         {
     59             edge[i].Flow-=Min;
     60             edge[((i-1)^1)+1].Flow+=Min;
     61             f+=Min;
     62             low-=Min;
     63         }
     64     return f;
     65 }
     66 
     67 int Dinic(int s,int e)
     68 {
     69     int Ans=0;
     70     while (Bfs(s,e))
     71             Ans+=Dfs(s,0x7fffffff);
     72     return Ans;
     73 }
     74 
     75 void Addline(int x)
     76 {
     77     memset(head,0,sizeof(head));
     78     memset(edge,0,sizeof(edge));
     79     num_edge=0;
     80     for (int i=1;i<=n;++i)
     81     {
     82         add(0,i+520,x);
     83         add(i+520,0,0);//超级源点 
     84         
     85         add(i+n+520,999,x);//超级汇点 
     86         add(999,i+n+520,0);
     87         
     88         add(i+520,i+250,k);
     89         add(i+250,i+520,0);
     90         
     91         add(i+n+250,i+n+520,k);
     92         add(i+n+520,i+n+250,0); 
     93     }
     94     for (int i=1;i<=n;++i)
     95     {
     96         for (int j=1;j<=n;++j)
     97             if (a[i][j]==1)
     98             {
     99                 add(i+520,j+n+520,1);
    100                 add(j+n+520,i+520,0);
    101             }
    102             else
    103             {
    104                 add(i+250,j+n+250,1);
    105                 add(j+n+250,i+250,0);
    106             }
    107     }
    108 }
    109 
    110 int main()
    111 {
    112     s=0,e=999;
    113     memset(&INF,0x7f,sizeof(INF));
    114     scanf("%d%d",&n,&k);
    115     for (int i=1;i<=n;++i)
    116     {
    117         scanf("%s",ch);
    118         for (int j=1;j<=n;++j)
    119             a[i][j]=(ch[j-1]=='Y');
    120     }
    121     int l=0,r=n*n;
    122     while (l<r)
    123     {
    124         int mid=(l+r+1)/2;
    125         Addline(mid);
    126         int Max=Dinic(0,999);
    127         if (Max==mid*n)
    128             l=mid;
    129         else
    130             r=mid-1;
    131     }
    132     printf("%d",l);
    133 }
  • 相关阅读:
    Java之hashCode的作用和equals方法的重构规则
    Java-IO流之File操作和Properties操作
    Java-IO流之转换流的使用和编码与解码原理
    Java-IO 字节流的使用和效率比较
    Java-IO流之BufferedReader 和BufferedWriter的使用和原理
    二分查找
    leetcode530 二叉搜索树的最小绝对差
    leetcode94 二叉树的中序遍历
    leetcode17电话号码字母组合
    leetcode26 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/refun/p/8678677.html
Copyright © 2020-2023  润新知