码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3081 Marriage Match II(网络流+并查集+二分答案)

时间:2017-11-26 16:54:37      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:can   push   lin   oge   ++   contains   case   标记   std   

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081

题目:

Problem 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 playing together. And it is normal that a fight or a quarrel breaks out, but we will still play together after that, because we are kids.
Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend.
Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on.
Now, here is the question for you, how many rounds can these 2n kids totally play this game?
 
Input
There are several test cases. First is a integer T, means the number of test cases.
Each test case starts with three integer n, m and f in a line (3<=n<=100,0<m<n*n,0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n).
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other.
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends.
 
Output
For each case, output a number in one line. The maximal number of Marriage Match the children can play.
 
Sample Input
1
4 5 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3
 
Sample Output
2
题意:n个男生和n个女生选伴侣。(女士优先)女生选择和自己没有吵过架的男生或者选择和自己朋友没有吵过架的男生。问最多有多少种选择方案能使得这n个女生和n个男生全部匹配完成。
题解:首先,先并查集把女生们分为若干个集合,每个的集合里面能匹配的男生都是共享的,标记一下。然后二分答案,构图:创建一个超级源点,把超级源点和每个女生连接,容量为mid;
每个女生和能匹配的男生都连接起来,容量为1;创建一个超级汇点,把每个男生和超级汇点连接,容量为mid。最后跑下网络流,判断下最大流量是否等于n*mid。
  1 //HDU 3081
  2 #include <queue>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <iostream>
  6 #include <algorithm>
  7 using namespace std;
  8 
  9 const int N=2333;
 10 const int M=233333;
 11 const int INF=0x3f3f3f3f;
 12 int n,m,f,s,t,cnt;
 13 int Head[N],Depth[N],cur[N],Father[N];
 14 int Next[M],V[M],W[M];
 15 bool Map[N][N];
 16 
 17 int Find(int x){return x==Father[x]?x:Father[x]=Find(Father[x]);}
 18 void Union(int x,int y){
 19     int fx=Find(x),fy=Find(y);
 20     if(fx!=fy){
 21         Father[fx]=fy;
 22     }
 23 }
 24 
 25 void init(){
 26     cnt=-1;
 27     memset(Head,-1,sizeof(Head));
 28     memset(Next,-1,sizeof(Next));
 29 }
 30 
 31 void add_edge(int u,int v,int w){
 32     cnt++;Next[cnt]=Head[u];V[cnt]=v;W[cnt]=w;Head[u]=cnt;
 33     cnt++;Next[cnt]=Head[v];V[cnt]=u;W[cnt]=0;Head[v]=cnt;
 34 }
 35 
 36 bool bfs(){
 37     queue <int> Q;
 38     while(!Q.empty()) Q.pop();
 39     memset(Depth,0,sizeof(Depth));
 40     Depth[s]=1;
 41     Q.push(s);
 42     while(!Q.empty()){
 43         int u=Q.front();Q.pop();
 44         for(int i=Head[u];i!=-1;i=Next[i]){
 45             if((W[i]>0)&&(Depth[V[i]]==0)){
 46                 Depth[V[i]]=Depth[u]+1;
 47                 Q.push(V[i]);
 48             }
 49         }
 50     }
 51     if(Depth[t]==0) return 0;
 52     return 1;
 53 }
 54 
 55 int dfs(int u,int dist){
 56     if(u==t) return dist;
 57     for(int& i=cur[u];i!=-1;i=Next[i]){
 58         if((Depth[V[i]]==Depth[u]+1)&&W[i]!=0){
 59             int di=dfs(V[i],min(dist,W[i]));
 60             if(di>0){
 61                 W[i]-=di;
 62                 W[i^1]+=di;
 63                 return di;
 64             }
 65         }
 66     }
 67     return 0;
 68 }
 69 
 70 int Dinic(){
 71     int ans=0;
 72     while(bfs()){
 73         for(int i=0;i<=2*n+1;i++) cur[i]=Head[i];
 74         while(int d=dfs(s,INF)) ans+=d;
 75     }
 76     return ans;
 77 }
 78 
 79 int check(int k){
 80     init();
 81     for(int i=1;i<=n;i++)
 82     for(int j=1+n;j<=2*n;j++)
 83     if(Map[i][j]) add_edge(i,j,1);
 84 
 85     for(int i=1;i<=n;i++) add_edge(s,i,k);
 86     for(int i=1+n;i<=2*n;i++) add_edge(i,t,k);
 87 
 88     if(Dinic()==k*n) return 1;
 89     else return 0;
 90 }
 91 
 92 int main(){
 93     int T,a,b;
 94     scanf("%d",&T);
 95     while(T--){
 96         memset(Map,0,sizeof(Map));
 97         for(int i=0;i<N;i++) Father[i]=i;
 98         scanf("%d %d %d",&n,&m,&f);
 99         for(int i=1;i<=m;i++){
100             scanf("%d %d",&a,&b);
101             Map[a][b+n]=1;
102         }
103         for(int i=1;i<=f;i++){
104             scanf("%d %d",&a,&b);
105             Union(a,b);
106         }
107         for(int i=1;i<=n;i++)
108         for(int j=i+1;j<=n;j++)
109             if(Find(i)==Find(j)){
110                 for(int k=1+n;k<=2*n;k++){
111                     Map[i][k]=Map[j][k]=(Map[i][k]||Map[j][k]);
112                 }
113             }
114         int s=0;t=2*n+1;
115         int l=0,r=111,mid;
116         while(r-l>1){
117             mid=(l+r)/2;
118             if(check(mid)) l=mid;
119             else r=mid;
120         }
121         printf("%d\n",l);
122     }
123     return 0;
124 }

//还有一种匈牙利的方法(二分图最大匹配),如果跑完完全匹配,答案+1,拆掉这种方案的所有边,然后接着跑,直到没有能完全匹配。

 

HDU 3081 Marriage Match II(网络流+并查集+二分答案)

标签:can   push   lin   oge   ++   contains   case   标记   std   

原文地址:http://www.cnblogs.com/Leonard-/p/7899200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!