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\n",low);
161     }
162 }

原文地址:https://www.cnblogs.com/computer-luo/p/9765698.html

时间: 2024-08-27 13:38:59

HDU 3081 Marriage Match II <<二分最大流 + 并查集的相关文章

HDU 3081 Marriage Match II 二分+最大流

题目来源:HDU 3081 Marriage Match II 题意: 思路: 错误代码 纠结不知道哪错了 先放一放 #include <cstdio> #include <queue> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1010; const int INF = 999999999; st

HDU - 3081 Marriage Match II(二分图最大匹配 + 并查集)

题目大意:有n个男生n个女生,现在要求将所有的男女配对,所有的男女都配对的话,算该轮游戏结束了.接着另一轮游戏开始,还是男女配对,但是配对的男女不能是之前配对过的. 问这游戏能玩多少轮 男女能配对的条件如下 1.男女未曾吵架过. 2.如果两个女的是朋友,那么另一个女的男朋友可以和该女的配对 解题思路:并查集解决朋友之间的关系,找到能配对的所有情况 接着二分图匹配,找到一个完美匹配算玩了一轮游戏,接着将这完美匹配的边删掉,继续进行匹配 如果无法完美匹配了,表示游戏结束了 #include <cst

hdu 3081 Marriage Match II(最大流 + 二分 + 并查集)

Marriage Match II                                                                           Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Presumably, you all have known the question of stable

HDU 3081 Marriage Match II 二分 + 网络流

Marriage Match II 题意:有n个男生,n个女生,现在有 f 条男生女生是朋友的关系, 现在有 m 条女生女生是朋友的关系, 朋友的朋友是朋友,现在进行 k 轮游戏,每轮游戏都要男生和女生配对,每轮配对过的人在接下来中都不能配对,求这个k最大是多少. 题解:二分 + 网络流check . 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt",

hdu 3277 Marriage Match III【最大流+并查集+二分枚举】

Marriage Match III Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1491    Accepted Submission(s): 440 Problem Description Presumably, you all have known the question of stable marriage match.

HDU 3081 Marriage Match II(二分+最大流)

HDU 3081 Marriage Match II 题目链接 题意:n个女孩n个男孩,每个女孩可以和一些男孩配对,然后有些女孩是朋友,满足这个朋友圈里面的人,如果有一个能和某个男孩配对,其他就都可以,然后每轮要求每个女孩匹配到一个男孩,且每轮匹配到的都不同,问最多能匹配几轮 思路:二分轮数k,然后建图为,源点连向女孩,男孩连向汇点容量都为k,然后女孩和男孩之间连边为,有关系的连边容量1,这样一个匹配对应一条边,且不会重复,每次判断最大流是否等于n * k即可 代码: #include <cst

hdu 3081 Marriage Match II (二分+最大流+并查集)

hdu 3081 Marriage Match II Description Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends p

HDU 3081 Marriage Match II(二分法+最大流量)

HDU 3081 Marriage Match II pid=3081" target="_blank" style="">题目链接 题意:n个女孩n个男孩,每一个女孩能够和一些男孩配对.然后有些女孩是朋友.满足这个朋友圈里面的人,假设有一个能和某个男孩配对,其它就都能够,然后每轮要求每一个女孩匹配到一个男孩.且每轮匹配到的都不同,问最多能匹配几轮 思路:二分轮数k,然后建图为,源点连向女孩,男孩连向汇点容量都为k,然后女孩和男孩之间连边为.有关系的

HDU 3081 Marriage Match II

Marriage Match II Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 308164-bit integer IO format: %I64d      Java class name: Main Presumably, you all have known the question of stable marriage match. A girl wi