HDU 3081 Marriage Match II

题意:有N个男孩,N个女孩。每个女孩可以选择一个没有跟他吵过架的男孩结婚。如果女孩X和女孩Y是朋友,且Y没有和男孩Z吵过架,女孩X同样可以选择男孩Z和自己结婚。另外,如果A和B是朋友,B和C是朋友,那么A和C也必定是朋友。一旦所有的女孩都找到了男友,那么他们就可以开始一轮新的游戏了,在每一轮新的游戏中,他们将使用相同的规则进行游戏,但是所有的女孩都不会选择之前选择过的男友了。问他们最多可以进行几轮游戏。

可以二分游戏的轮次数。首先做floyd闭包传递,确定女孩i可以与哪些男孩j配对。假设一共可以进行k轮游戏,那么从起点S向每个女孩i连一条边(S,i,k),从每个男孩向汇点T连一条边(i,T,k)。如果女孩i可以和男孩j配对,那么对应一条边(i,j,1)。跑最大流得到maxflow,如果maxflow=N*k,则说明可以进行k轮游戏。然后二分k就可以了。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define INF 1<<30
  6 #define maxn 210
  7 #define maxm 200000
  8 using namespace std;
  9 
 10 int v[maxm],next[maxm],w[maxm];
 11 int first[maxn],d[maxn],work[maxn],q[maxn];
 12 int e,S,T;
 13 int n,m,f;
 14 int like[110][110],map[110][110];
 15 void init(){
 16     e = 0;
 17     memset(first,-1,sizeof(first));
 18 }
 19 
 20 void add_edge(int a,int b,int c){
 21     //printf("add:%d to %d,cap = %d
",a,b,c);
 22     v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++;
 23     v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++;
 24 }
 25 
 26 int bfs(){
 27     int rear = 0;
 28     memset(d,-1,sizeof(d));
 29     d[S] = 0;q[rear++] = S;
 30     for(int i = 0;i < rear;i++){
 31         for(int j = first[q[i]];j != -1;j = next[j])
 32             if(w[j] && d[v[j]] == -1){
 33                 d[v[j]] = d[q[i]] + 1;
 34                 q[rear++] = v[j];
 35                 if(v[j] == T)   return 1;
 36             }
 37     }
 38     return 0;
 39 }
 40 
 41 int dfs(int cur,int a){
 42     if(cur == T)    return a;
 43     for(int &i = work[cur];i != -1;i = next[i]){
 44         if(w[i] && d[v[i]] == d[cur] + 1)
 45             if(int t = dfs(v[i],min(a,w[i]))){
 46                 w[i] -= t;w[i^1] += t;
 47                 return t;
 48             }
 49     }
 50     return 0;
 51 }
 52 
 53 int dinic(){
 54     int ans = 0;
 55     while(bfs()){
 56         memcpy(work,first,sizeof(first));
 57         while(int t = dfs(S,INF))   ans += t;
 58     }
 59     return ans;
 60 }
 61 
 62 void floyd(){
 63     for(int k = 1;k <= n;k++)
 64     for(int i = 1;i <= n;i++)   if(map[i][k])
 65     for(int j = 1;j <= n;j++)   if(map[k][j])
 66     map[i][j] = 1;
 67 
 68     for(int k = 1;k <= n;k++)
 69     for(int i = 1;i <= n;i++)   if(map[i][k])
 70     for(int j = 1;j <= n;j++)   if(like[k][j])
 71     like[i][j] = 1;
 72 }
 73 
 74 bool test(int mid){
 75     init();
 76     for(int i = 1;i <= n;i++)
 77         add_edge(S,i,mid);
 78     for(int i = n+1;i <= 2*n;i++)
 79         add_edge(i,T,mid);
 80     for(int i = 1;i <= n;i++){
 81         for(int j = 1;j <= n;j++)   if(like[i][j])
 82             add_edge(i,j+n,1);
 83     }
 84     int ans = dinic();
 85     if(ans == mid*n)    return true;
 86     return false;
 87 }
 88 int main()
 89 {
 90     int kase;
 91     scanf("%d",&kase);
 92     while(kase--){
 93         scanf("%d%d%d",&n,&m,&f);
 94         S = 0,T = 2*n+1;
 95         memset(map,0,sizeof(map));
 96         memset(like,0,sizeof(like));
 97         for(int i = 0;i < m;i++){
 98             int a,b;
 99             scanf("%d%d",&a,&b);
100             like[a][b] = 1;
101         }
102         for(int i = 0;i < f;i++){
103             int a,b;
104             scanf("%d%d",&a,&b);
105             map[a][b] = map[b][a] = 1;
106         }
107         floyd();
108         int L = 0,R = n,ans = 0;
109         while(L <= R){
110             int mid = (L+R)>>1;
111             if(test(mid)){
112                 ans = mid;
113                 L = mid+1;
114             }
115             else R = mid-1;
116         }
117         printf("%d
",ans);
118     }
119     return 0;
120 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3390748.html