HDU 3277 Marriage Match III

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

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

HDU 3081 Marriage Match II  

不同的是,女生交换朋友的时候也不能和争吵过得男生组成家庭。

问能交换多少次。

题解:与3081那道题主要不同的地方是多了拆点。

   建边:将女生拆点为女生1,女生2。源点和女生1建边,边权依旧是mid;男生和汇点建边,边权是mid;女生1和女生2建边,边权是K;如果女生和男生可以组成家庭,女生1和男生建       边,边权为1,否则女生2和男生建边,边权为2。

T了很多发……优化了并查集的判断。抄了别人的ISAP的板子http://www.350351.com/bianchengyuyan/Cyuyan/318117.html

  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 const int maxm=10000010;
 23 const int maxn=260;
 24 
 25 struct edge{
 26     int u,v,cap,next;
 27 }G[maxm];
 28 struct node{
 29     int girl,boy;
 30 }friend1[maxm];
 31 int judge[maxn][maxn];
 32 int idx;
 33 int head[maxn*maxn],level[maxn*maxn];
 34 int num[maxn*maxn];
 35 int cur[maxn*maxn];
 36 int pre[maxn*maxn];
 37 int s,t,tt;
 38 int par[maxn*maxn];
 39 int rankh[maxn*maxn];
 40 int N,M,K,F;
 41 
 42 void init(int n)
 43 {
 44     for(int i=0;i<=n;i++)
 45     {
 46         par[i]=i;
 47     }
 48 }
 49 
 50 int find(int x)
 51 {
 52     if(par[x]==x){
 53         return x;
 54     }else{
 55         return par[x]=find(par[x]);
 56     }
 57 }
 58 
 59 void unite(int x,int y)
 60 {
 61     x=find(x);
 62     y=find(y);
 63     if(x==y) return;
 64     else{
 65         par[x]=y;
 66     }
 67 }
 68 
 69 void build(int u,int v,int cap)
 70 {
 71     G[idx].v=v;
 72     G[idx].cap=cap;
 73     G[idx].next=head[u];
 74     head[u]=idx++;
 75 }
 76 
 77 void add_edge(int u,int v,int cap)
 78 {
 79     build(u,v,cap);
 80     build(v,u,0);
 81 }
 82 
 83 
 84 void bfs()
 85 {
 86     memset(level,-1,sizeof(level));
 87     memset(num,0,sizeof(num));
 88     queue<int>q;
 89     q.push(t);
 90     level[t]=0;
 91     num[0]=1;
 92     while(!q.empty())
 93     {
 94         int u=q.front();
 95         q.pop();
 96         for(int i=head[u];i!=-1;i=G[i].next)
 97         {
 98             int v=G[i].v;
 99             if(level[v]==-1)
100             {
101                 level[v]=level[u]+1;
102                 num[level[v]]++;
103                 q.push(v);
104             }
105         }
106     }
107 }
108 
109 int ISAP()
110 {
111     memcpy(cur,head,sizeof(cur));
112     bfs();
113     int flow=0;
114     int u=pre[s]=s;
115     while(level[s]<tt)
116     {
117         if(u==t){
118             int f=INF,pos;
119             for(int i=s;i!=t;i=G[cur[i]].v)
120             {
121                 if(f>G[cur[i]].cap){
122                     f=G[cur[i]].cap;
123                     pos=i;
124                 }
125             }
126             for(int i=s;i!=t;i=G[cur[i]].v)
127             {
128                 G[cur[i]].cap-=f;
129                 G[cur[i]^1].cap+=f;
130             }
131             flow+=f;
132             u=pos;
133         }
134         int i;
135         for(i=cur[u];i!=-1;i=G[i].next)
136         {
137             if(level[G[i].v]+1==level[u]&&G[i].cap) break;
138         }
139         if(i!=-1){
140             cur[u]=i;
141             pre[G[i].v]=u;
142             u=G[i].v;
143         }
144         else{
145             if(--num[level[u]]==0) break;
146             int mind=tt;
147             for(int i=head[u];i!=-1;i=G[i].next)
148             {
149                 if(mind>level[G[i].v]&&G[i].cap){
150                     mind=level[G[i].v];
151                     cur[u]=i;
152                 }
153             }
154             level[u]=mind+1;
155             num[level[u]]++;
156             u=pre[u];
157         }
158     }
159     return flow;
160 }
161 
162 void build_graph(int cap)
163 {
164     memset(head,-1,sizeof(head));
165     idx=0;
166     for(int i=1;i<=N;i++)
167     {
168         for(int j=1;j<=N;j++)
169         {
170             if(judge[find(i)][j]){
171                 add_edge(i,2*N+j,1);
172             }
173             else{
174                 add_edge(N+i,2*N+j,1);
175             }
176         }
177     }
178     for(int i=1;i<=N;i++)
179     {
180         add_edge(s,i,cap);//源点-女生(1~N)
181         add_edge(2*N+i,t,cap);//男生-汇点(2*N+1~3*N)
182         add_edge(i,N+i,K);//女生1-女生2
183     }
184 }
185 
186 int main()
187 {
188    // freopen("/Users/apple/Desktop/暑假/27(2)/27(2)/in","r",stdin);
189     int T;
190     scanf("%d",&T);
191     while(T--)
192     {
193         scanf("%d%d%d%d",&N,&M,&K,&F);
194         s=0;
195         t=3*N+1;
196         tt=t+1;
197         memset(judge,0,sizeof(judge));
198         
199         for(int i=0;i<M;i++)
200             scanf("%d%d",&friend1[i].girl,&friend1[i].boy);
201         
202         init(3*N);
203         
204         for(int i=0;i<F;i++)
205         {
206             int g1,g2;
207             scanf("%d%d",&g1,&g2);
208             unite(g1,g2);
209         }
210         for(int i=0;i<M;i++)
211         {
212             int x=friend1[i].girl,y=friend1[i].boy;
213             judge[find(x)][y]=1;
214         }
215         
216         int low=0;
217         int high=N;
218         int res=0;
219         while(low<=high)
220         {
221             int mid=(low+high)/2;
222             build_graph(mid);
223             if(ISAP()>=N*mid) {
224                 res=mid;
225                 low=mid+1;
226             }
227             else{
228                 high=mid-1;
229             }
230         }
231         printf("%d\n",res);
232     }
233     
234     return 0;
235 }

 

posted @ 2014-08-04 16:21  Der_Z  阅读(224)  评论(0编辑  收藏  举报