1. 程式人生 > >HDU 3081 Marriage Match II(網絡流+並查集+二分答案)

HDU 3081 Marriage Match II(網絡流+並查集+二分答案)

you 集合 more cst ott next friends nic problem

題目鏈接: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(網絡流+並查集+二分答案)