zoukankan      html  css  js  c++  java
  • HDU 3081 Marriage Match II <<二分最大流 + 并查集

    题意

    n个女孩子跟n个男孩子过家家,女孩子选男孩子,告诉你每个女孩子可选的男孩子与女孩子之间的好友关系,好友关系是互相的而且是传递的,然后如果两个女孩子是好友,他们可选的男孩子也是可以合并的。然后每一轮进行匹配,匹配成功后开始下一轮,每个女孩子只能选同一个男孩子一次,问最多能玩几轮。

    思路

    首先,好友关系的建立显然就直接想到了用并查集处理。

    然后在建图时,可以选择是二分图,然后跑完备匹配,每次匹配完后删除匹配边进行下一次匹配。

    当然,不会二分图的我就选择直接跑网络流啦,但是建图时候发现需要知道流量,这时候,就是二分答案的地方了。

    具体建图:

    从S向i建容量为K的边,从i向每个与他能匹配的i+n建容量为1的边,最后从i+n到T建容量为K的边

    通过判断是否满流,来判断当前K是否可行,即判断maxflow==K*n

    代码

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn=205;
      4 const int INF=0x3f3f3f3f;
      5 struct Edge{
      6     int from,to,cap,flow;
      7 };
      8 struct DINIC{
      9     int n,m,s,t;
     10     vector<Edge> edges;
     11     vector<int> G[maxn];
     12     bool vis[maxn];
     13     int d[maxn];
     14     int cur[maxn];
     15 
     16     void init()
     17     {
     18         edges.clear();
     19         for(int i=0;i<maxn;i++)
     20             G[i].clear();
     21     }
     22     void AddEdge(int from,int to,int cap,int c=0)
     23     {
     24         edges.push_back(Edge {from,to,cap,0});
     25         edges.push_back(Edge {to,from,c,0});
     26         m=edges.size();
     27         G[from].push_back(m-2);
     28         G[to].push_back(m-1);
     29     }
     30 
     31     bool BFS()
     32     {
     33         memset(vis,0,sizeof(vis));
     34         queue<int> Q;
     35         Q.push(s);
     36         d[s]=0;
     37         vis[s]=1;
     38         while(!Q.empty())
     39         {
     40             int x=Q.front();Q.pop();
     41             for(int i=0;i<G[x].size();i++)
     42             {
     43                 Edge& e=edges[G[x][i]];
     44                 if(!vis[e.to]&&e.cap>e.flow)
     45                 {
     46                     vis[e.to]=1;
     47                     d[e.to]=d[x]+1;
     48                     Q.push(e.to);
     49                 }
     50             }
     51         }
     52         return vis[t];
     53     }
     54 
     55     int DFS(int x,int a)
     56     {
     57         if(x==t||a==0) return a;
     58         int flow=0,f;
     59         for(int& i=cur[x];i<G[x].size();i++)
     60         {
     61             Edge& e=edges[G[x][i]];
     62             if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
     63             {
     64                 e.flow+=f;
     65                 edges[G[x][i]^1].flow-=f;
     66                 flow+=f;
     67                 a-=f;
     68                 if(a==0) break;
     69             }
     70         }
     71         return flow;
     72     }
     73     int Maxflow(int s,int t)
     74     {
     75         this->s=s;this->t=t;
     76         int flow=0;
     77         while(BFS())
     78         {
     79             memset(cur,0,sizeof(cur));
     80             flow+=DFS(s,INF);
     81         }
     82         return flow;
     83     }
     84 }ANS;
     85 int N,F,M,SS,TT;
     86 int far[105];
     87 bool dist[maxn][maxn];
     88 void init()
     89 {
     90     memset(dist,0,sizeof(dist));
     91     for(int i=0;i<=N;i++)
     92     {
     93         far[i]=i;
     94     }
     95 }
     96 int Find(int x)
     97 {
     98     if(far[x]==x) return x;
     99     else return far[x]=Find(far[x]);
    100 }
    101 void Union(int x,int y)
    102 {
    103     x=Find(x),y=Find(y);
    104     if(x!=y) far[y]=x;
    105 }
    106 void build(int now)
    107 {
    108     ANS.init();
    109     for(int i=1;i<=N;i++)
    110     {
    111         ANS.AddEdge(SS,i,now);
    112         for(int j=N+1;j<=N*2;j++)
    113             if(dist[i][j]) ANS.AddEdge(i,j,1);
    114     }
    115     for(int i=N+1;i<=2*N;i++)
    116         ANS.AddEdge(i,TT,now);
    117 }
    118 bool check(int now)
    119 {
    120     build(now);
    121     return ANS.Maxflow(SS,TT)==N*now;
    122 }
    123 int main()
    124 {
    125     int T;
    126     scanf("%d",&T);
    127     while(T--)
    128     {
    129         scanf("%d%d%d",&N,&M,&F);
    130         SS=0,TT=2*N+1;
    131         init();
    132         int low=0,high=N+1;
    133         for(int i=0,u,v;i<M;i++)
    134         {
    135             scanf("%d%d",&u,&v);
    136             dist[u][v+N]=1;
    137         }
    138         for(int i=1,u,v;i<=F;i++)//并查集操作
    139         {
    140             scanf("%d%d",&u,&v);
    141             Union(u,v);
    142         }
    143         for(int i=1;i<=N;i++)//合并共用边,这里是抄网上大佬的
    144         {
    145             for(int j=i+1;j<=N;j++)
    146             {
    147                 if(Find(i)==Find(j))
    148                 {
    149                     for(int k=N+1;k<=N*2;k++)
    150                         dist[i][k]=dist[j][k]=(dist[i][k]||dist[j][k]);
    151                 }
    152             }
    153         }
    154         while(high-low>1)//二分
    155         {
    156             int mid=(low+high)>>1;
    157             if(check(mid)) low=mid;
    158             else high=mid;
    159         }
    160         printf("%d
    ",low);
    161     }
    162 }
  • 相关阅读:
    2020重新出发,MySql基础,MySql用户管理
    2020重新出发,MySql基础,MySql字符集
    2020重新出发,MySql基础,MySql事务
    python全栈day10
    python全栈day9
    python全栈day8
    python全栈day7
    python全栈day6
    python全栈day5
    python全栈day4
  • 原文地址:https://www.cnblogs.com/computer-luo/p/9765698.html
Copyright © 2011-2022 走看看