zoukankan      html  css  js  c++  java
  • HDU3277Marriage Match III并查集+二分+最大流

    题意:

    n个女孩要与n个男孩玩配对游戏.每个女孩有一个可选男孩的集合(即该女孩可以选自己喜欢集合中的任意一个男孩作为该轮的搭档),还能选自己喜欢的男孩外还能选任意K个自己不喜欢的男孩.

    然后从第一轮开始,每个女孩都要和一个不同的男孩配对.如果第一轮n个女孩都配对成功,那么就开始第二轮配对,女孩依然从自己的备选男孩集合中选择,但是不能选那些已经被该女孩在前几轮选择中选过的男孩了。问游戏最多能进行多少轮?

    思路:

    给出n,m,k,f,之后会给出m行x、y,代表编号x的girl可以和编号为y的男孩配对--------->>用ee数组做标记,代表x可以和y配对

    f 行x、y,表示女孩子x和女孩子y是好朋友。因为女孩是抱团的,即女孩a如果和女孩b是好朋友,且女孩a可以和男孩a配对,那么女孩b也可以和男孩a配对----------->>所以利用并查集将是好朋友的女生合并

    这道题目在Marriage Match II的基础上增添了一个条件:女孩子还可以选任意K个自己不喜欢的男孩,

    之前Marriage Match II可以用匈牙利算法做,但是这道题目需要建图

    防止超时,所以二分枚举答案,

    源点s编号0,女孩i分成两个点i和i+n编号(编号i的点用来连接该女孩喜欢的男孩,编号为i+n的点用来连接该女孩不喜欢的男孩), 男孩编号为2n+1到2n+n, 汇点t编号为3n+1.

    首先源点s到第i个女孩有边(s, i, mid)

    第i个女孩的i点到i+n点有边(i, i+n, k)

    如果第i个女孩可以选男孩j,那么有边(i, j, 1). 否则有边(i+n, j, 1)

    每个男孩j到汇点t有边(j, t, mid)

    最后看所求的dinic最大流是否等于mid*n即可。

    e[i][j]==1 表示第i个女孩可以选第j个男孩. 这里的可选指的是女孩没和男孩吵架或女孩的朋友没和男孩吵架.)

    强调!!!

    1. 一定要初始化一开始,因为并查集的原因,否则结果还是不对;
    2. 之后建图枚举答案的时候,需要改变一点点dinic的模板,因为是枚举答案,每次的枚举都会在原有的建图上进行add添边从而造成结果错误,正确做法应该是在每次枚举的时候都清空,即重新建图添边。

    AC代码:

      1 #include<stdio.h>
      2 #include<iostream>
      3 #include<queue>
      4 #include<string.h>
      5 using namespace std;
      6 #define inf 0x3f3f3f3f
      7 
      8 const int N=300;
      9 int n,s,t,k,tot,f[N],ee[N][N];
     10 int head[10*N],dep[10*N],cur[10*N];
     11 struct node
     12 {
     13     int nextt,v,flow;
     14 } e[N*N];
     15 
     16 int getf(int x)
     17 {
     18     if(f[x]==x)
     19         return x;
     20     return f[x]=getf(f[x]);
     21 }
     22 
     23 void merge(int x,int y)
     24 {
     25     int t1=getf(x);
     26     int t2=getf(y);
     27     f[t2]=t1;
     28 }
     29 
     30 struct Dinic
     31 {
     32     void init()
     33     {
     34         tot=-1,s=0,t=n*3+1;
     35         for(int i=1; i<=n; i++)
     36             f[i]=i;
     37         memset(head,-1,sizeof(head));
     38     }
     39 
     40     void add(int u,int v,int flow)
     41     {
     42         tot++;
     43         e[tot].nextt=head[u];
     44         head[u]=tot;
     45         e[tot].v=v;
     46         e[tot].flow=flow;
     47 
     48         tot++;
     49         e[tot].nextt=head[v];
     50         head[v]=tot;
     51         e[tot].v=u;
     52         e[tot].flow=0;
     53     }
     54 
     55     int dfs(int u,int flow)
     56     {
     57         if(u==t)
     58             return flow;
     59         for(int &i=cur[u]; i!=-1; i=e[i].nextt) //注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
     60         {
     61             if((dep[e[i].v]==dep[u]+1)&&e[i].flow>0)
     62             {
     63                 int di=dfs(e[i].v,min(flow,e[i].flow));
     64                 if(di>0)
     65                 {
     66                     e[i].flow-=di;
     67                     e[i^1].flow+=di;
     68                     return di;
     69                 }
     70             }
     71         }
     72         return 0;
     73     }
     74 
     75     bool bfs()
     76     {
     77         if(s==t)return 0;
     78         queue<int>Q;
     79         while(!Q.empty())
     80             Q.pop();
     81         memset(dep,-1,sizeof(dep));
     82         dep[s]=1;
     83         Q.push(s);
     84         while(!Q.empty())
     85         {
     86             int u=Q.front();
     87             Q.pop();
     88             for (int i=head[u]; i!=-1; i=e[i].nextt)
     89             {
     90                 if ((e[i].flow>0)&&(dep[e[i].v]==-1))
     91                 {
     92                     dep[e[i].v]=dep[u]+1;
     93                     Q.push(e[i].v);
     94                 }
     95             }
     96         }
     97         if(dep[t]!=-1)
     98             return 1;
     99         return 0;
    100     }
    101 
    102     int dinicc()
    103     {
    104         int sum=0;
    105         while(bfs())
    106         {
    107             for(int i=s; i<=t; i++)
    108                 cur[i]=head[i];
    109             int di;
    110             while((di=dfs(s,inf)))
    111                 sum+=di;
    112         }
    113         return sum;
    114     }
    115 } dinic;
    116 
    117 
    118 bool solve(int x)
    119 {
    120     dinic.init();
    121     for(int i=1; i<=n; i++)
    122     {
    123         dinic.add(s,i,x);
    124         dinic.add(i,i+n,k);
    125         dinic.add(2*n+i,t,x);
    126     }
    127     for(int i=1; i<=n; i++)
    128     {
    129         for(int j=1; j<=n; j++)
    130         {
    131             if(ee[i][j])
    132                 dinic.add(i,2*n+j,1);
    133             else
    134                 dinic.add(i+n,2*n+j,1);
    135         }
    136     }
    137     if(dinic.dinicc()==n*x)
    138         return 1;
    139     return 0;
    140 }
    141 
    142 int main()
    143 {
    144     int m,F,T;
    145     scanf("%d",&T);
    146     while(T--)
    147     {
    148         scanf("%d %d %d %d",&n,&m,&k,&F);
    149 //        init();
    150 //        dinic.init();
    151         for(int i=1; i<=n; i++)
    152             f[i]=i;
    153         memset(ee,0,sizeof(ee));
    154         for(int i=1; i<=m; i++) //girl and boy never quarrel
    155         {
    156             int x,y;
    157             scanf("%d %d",&x,&y);
    158             ee[x][y]=1;
    159         }
    160         for(int i=1; i<=F; i++)//x and y are friends
    161         {
    162             int x,y;
    163             scanf("%d %d",&x,&y);
    164             merge(x,y);
    165         }
    166         for(int i=1; i<=n; i++)
    167         {
    168             for(int j=i+1; j<=n; j++)
    169             {
    170                 if(getf(i)==getf(j))
    171                 {
    172                     for(int kk=1; kk<=n; kk++)
    173                     {
    174                         if(ee[i][kk]||ee[j][kk])
    175                             ee[i][kk]=ee[j][kk]=1;
    176                     }
    177                 }
    178             }
    179         }
    180         int L=0,R=n;
    181         while(L<=R)
    182         {
    183             int mid=(L+R)>>1;
    184             if(solve(mid))
    185                 L=mid+1;
    186             else
    187                 R=mid-1;
    188         }
    189         printf("%d\n",L-1);
    190     }
    191     return 0;
    192 }
    View Code
  • 相关阅读:
    Android应用程序执行流程
    Android的架构与Android应用程序启动流程
    Android开发环境使用工具Eclipse IDE工程目录结构
    MySQL 的 crash-safe 原理解析
    vivo 悟空活动中台
    图解 Promise 实现原理(三)—— Promise 原型方法实现
    领域驱动设计(DDD)实践之路(三):如何设计聚合
    深入浅出开源监控系统Prometheus(上)
    你还应该知道的哈希冲突解决策略
    反应式编程 RxJava 设计原理解析
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12701745.html
Copyright © 2011-2022 走看看