HDU 3081 Marriage Match II

http://acm.hdu.edu.cn/showproblem.php?pid=3081

题意:有2N个孩子,其中有N个女生,N个男生,每一个女生可以找一个没有争吵过得男生组成一个家庭,并且可以和与她关系好的女生互换男生。问能交换多少次。

题解:最少交换0次,最多交换2*N次。需要用并查集处理好女生直接的关系。然后二分,建立网络流。

   建边:源点和女生建边,容量为mid;女生和可以交换的男生建边,容量为1;男生和汇点建边,容量为mid。

   可行条件:如果最大流==N*mid,表示可以交换这么多次。

但是不知道为什么在unite()之后还要找一下每一个点的par??为什么???

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <string>
  7 #include <vector>
  8 #include <list>
  9 #include <map>
 10 #include <queue>
 11 #include <stack>
 12 #include <bitset>
 13 #include <algorithm>
 14 #include <numeric>
 15 #include <functional>
 16 #include <set>
 17 #include <fstream>
 18 
 19 using namespace std;
 20 
 21 const int INF=0xfffffff;
 22 
 23 const int maxn=510;
 24 const int maxm=50010;
 25 
 26 struct edge{
 27     int to,next,cap;
 28 }G[maxm];
 29 struct node{
 30     int girl,boy;
 31 }friend1[maxm];
 32 int judge[maxn][maxn];
 33 int head[maxn],idx,sum;
 34 int level[maxn];
 35 int gap[maxn];
 36 int par[maxn];
 37 int rankh[maxn];
 38 int N,M,F;
 39 int s,t;
 40 
 41 void add_edge(int from,int to,int cap)
 42 {
 43     G[idx].to=to;
 44     G[idx].cap=cap;
 45     G[idx].next=head[from];
 46     head[from]=idx++;
 47     
 48     G[idx].to=from;
 49     G[idx].cap=0;
 50     G[idx].next=head[to];
 51     head[to]=idx++;
 52 }
 53 
 54 int dfs(int pos,int cost,int cnt)
 55 {
 56     if(pos==t)
 57     {
 58         return cost;
 59     }
 60     int minh=cnt-1;
 61     int lv=cost;
 62     int d;
 63     for(int j=head[pos];j!=-1;j=G[j].next)
 64     {
 65         int v=G[j].to,cap=G[j].cap;
 66         if(cap>0)
 67         {
 68             if(level[v]+1==level[pos])
 69             {
 70                 if(lv<G[j].cap) d=lv;
 71                 else d=G[j].cap;
 72                 
 73                 d=dfs(v,d,cnt);
 74                 G[j].cap-=d;
 75                 G[j^1].cap+=d;
 76                 lv-=d;
 77                 if(level[s]>=cnt) return cost-lv;
 78                 if(lv==0) break;
 79             }
 80             if(level[v]<minh) minh=level[v];
 81         }
 82     }
 83     if(lv==cost)
 84     {
 85         --gap[level[pos]];
 86         if(gap[level[pos]]==0) level[s]=cnt;
 87         level[pos]=minh+1;
 88         ++gap[level[pos]];
 89     }
 90     
 91     return cost-lv;
 92 }
 93 
 94 int sap(int s,int t,int cnt)
 95 {
 96     int flow=0;
 97     gap[s]=cnt;
 98     while(level[s]<cnt)
 99     {
100         flow+=dfs(s,INF,cnt);
101     }
102     //printf("...%d
",flow);
103     return flow;
104 }
105 
106 void initu(int n)
107 {
108     for(int i=0;i<=n;i++)
109     {
110         par[i]=i;
111         rankh[i]=0;
112     }
113 }
114 
115 int find(int x)
116 {
117     if(par[x]==x){
118         return x;
119     }
120     else{
121         return par[x]=find(par[x]);
122     }
123 }
124 
125 void unite(int x,int y)
126 {
127     x=find(x);
128     y=find(y);
129     if(x==y) return;
130     if(rankh[x]<rankh[y]){
131         par[x]=y;
132         rankh[y]+=rankh[x];
133     }
134     else{
135         par[y]=x;
136 //        rankh[x]++;
137         rankh[x]+=rankh[y];
138     }
139 }
140 
141 void build(int cap)
142 {
143     s=0;
144     t=2*N+1;
145     idx=0;
146     memset(gap,0,sizeof(gap));
147     memset(level,0,sizeof(level));
148     memset(head,-1,sizeof(head));
149     memset(judge,0,sizeof(judge));
150     for(int i=1;i<=N;i++)
151     {
152         add_edge(s,i,cap);
153         add_edge(N+i,t,cap);
154     }
155     for(int i=1;i<=M;i++)
156     {
157         int x=friend1[i].girl;
158         int y=friend1[i].boy;
159         for(int j=1;j<=N;j++)
160         {
161             if(par[x]==par[j]&&!judge[j][y]){
162                 add_edge(j,N+y,1);
163                 judge[j][y]=1;
164             }
165         }
166     }
167 }
168 
169 int main()
170 {
171     //freopen("/Users/apple/Desktop/暑假/26.1/26.1/in","r",stdin);
172     int T;
173     scanf("%d",&T);
174     while(T--)
175     {
176         scanf("%d%d%d",&N,&M,&F);
177         for(int i=1;i<=M;i++)
178             scanf("%d%d",&friend1[i].girl,&friend1[i].boy);
179         initu(2*N);
180         for(int i=0;i<F;i++)
181         {
182             int x,y;
183             scanf("%d%d",&x,&y);
184             unite(x,y);
185         }
186 //        for(int i=1;i<=2*N;i++)
187 //        {
188 //            //par[i]=find(i);
189 //            printf("%d %d
",i,par[i]);
190 //        }
191         for(int i=1;i<=2*N;i++)
192         {
193             par[i]=find(i);
194             //printf("%d %d
",i,par[i]);
195         }
196 //        for(int i=1;i<=2*N;i++)
197 //        {
198 //            //par[i]=find(i);
199 //            printf("----%d %d
",i,par[i]);
200 //        }
201         int low=0;
202         int high=N;
203         int res=0;
204         while(low<=high)
205         {
206             int mid=(low+high)/2;
207             build(mid);
208             if(sap(s,t,t+1)==N*mid)
209             {
210                 low=mid+1;
211                 res=mid;
212             }
213             else
214                 high=mid-1;
215         }
216         printf("%d
",res);
217     }
218     return 0;
219 }
原文地址:https://www.cnblogs.com/der-z/p/3885140.html