hdu 3081(二分+最大流+并查集)

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

思路设源点为0,汇点为2*n+1,对没吵过架的女生和男生连容量为1的边(这里要用到并查集,每个女生的朋友也可以和该男生连边),然后就是源点与女生连边,容量为mid(0<=mid<=n),男生与汇点也连容量为mid的边(这里的mid即为为每个男孩和女孩找到了k个不同的伴侣,说明游戏可以进行k轮,附上链接:http://blog.csdn.net/qq564690377/article/details/7857983),然后就是二分搜索了。

View Code
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 #define MAXN 222
  6 #define inf 1<<30
  7 int map[MAXN][MAXN];
  8 int mm[MAXN][MAXN];
  9 int pre[MAXN];
 10 int level[MAXN];
 11 int gap[MAXN];
 12 int parent[MAXN];
 13 int NV,n,m,f;
 14 
 15 void Initiate(){
 16     for(int i=1;i<=2*n;i++){
 17         parent[i]=-1;
 18     }
 19 }
 20 
 21 int Find(int x){
 22     int s;
 23     for(s=x;parent[s]>0;s=parent[s])
 24         ;
 25     while(x!=s){
 26         int tmp=parent[x];
 27         parent[x]=s;
 28         x=tmp;
 29     }
 30     return s;
 31 }
 32 
 33 void Union(int u,int v){
 34     int r1=Find(u);
 35     int r2=Find(v);
 36     if(r1==r2)return ;
 37     if(parent[r1]>parent[r2]){
 38         parent[r2]+=parent[r1];
 39         parent[r1]=r2;
 40     }else {
 41         parent[r1]+=parent[r2];
 42         parent[r2]=r1;
 43     }
 44 }
 45 
 46 
 47 int SAP(int vs,int vt){
 48     memset(pre,-1,sizeof(pre));
 49     memset(level,0,sizeof(level));
 50     memset(gap,0,sizeof(gap));
 51     int v,u=pre[vs]=vs,maxflow=0,aug=inf;
 52     gap[0]=NV;
 53     while(level[vs]<NV){
 54         for(v=1;v<=vt;v++){
 55             if(map[u][v]&&level[u]==level[v]+1){
 56                 break;
 57             }
 58         }
 59         if(v<=vt){
 60             pre[v]=u;
 61             u=v;
 62             if(v==vt){
 63                 aug=inf;
 64                 for(int i=v;i!=vs;i=pre[i]){
 65                     if(aug>map[pre[i]][i])aug=map[pre[i]][i];
 66                 }
 67                 maxflow+=aug;
 68                 for(int i=v;i!=vs;i=pre[i]){
 69                     map[pre[i]][i]-=aug;
 70                     map[i][pre[i]]+=aug;
 71                 }
 72                 u=vs;
 73             }
 74         }else {
 75             int minlevel=NV;
 76             for(int v=1;v<=vt;v++){
 77                 if(map[u][v]&&minlevel>level[v]){
 78                     minlevel=level[v];
 79                 }
 80             }
 81             gap[level[u]]--;
 82             if(gap[level[u]]==0)break;
 83             level[u]=minlevel+1;
 84             gap[level[u]]++;
 85             u=pre[u];
 86         }
 87     }
 88     return maxflow;
 89 }
 90 
 91 void Build(int k){
 92     memset(map,0,sizeof(map));
 93     for(int i=1;i<=n;i++){
 94         map[0][i]=k;
 95         map[i+n][2*n+1]=k;
 96     }
 97     for(int i=1;i<=n;i++){
 98         for(int j=n+1;j<=2*n;j++){
 99             map[i][j]=mm[i][j];
100         }
101     }
102     for(int i=1;i<=n;i++){
103         for(int j=1;j<=n;j++){
104             if(Find(i)==Find(j)){
105                 for(int k=n+1;k<=2*n;k++){
106                     if(map[i][k])map[j][k]=1;
107                 }
108             }
109         }
110     }
111 }
112 
113 
114 int Binary_Search(){
115     int low=0,high=n,tmp;
116     NV=2*n+2;
117     while(low<=high){
118         int mid=(low+high)/2;
119         Build(mid);
120         if(mid*n==SAP(0,2*n+1)){
121             tmp=mid;//这里需要保留mid值。
122             low=mid+1;
123         }else 
124             high=mid-1;
125     }
126     return tmp;
127 }
128 
129 
130 int main(){
131     int _case,g,b,g1,g2;
132     scanf("%d",&_case);
133     while(_case--){
134         scanf("%d%d%d",&n,&m,&f);
135         Initiate();
136         memset(map,0,sizeof(map));
137         memset(mm,0,sizeof(mm));
138         for(int i=1;i<=m;i++){
139             scanf("%d%d",&g,&b);
140             map[g][b+n]=1;
141             mm[g][b+n]=1;//保留原图,因为每次SAP之后,图就改变了。
142         }
143         for(int i=1;i<=f;i++){
144             scanf("%d%d",&g1,&g2);
145             if(Find(g1)!=Find(g2)){
146                 Union(g1,g2);
147             }
148         }
149         int ans=Binary_Search();
150         printf("%d\n",ans);
151     }
152     return 0;
153 }
154 
155         
156 
157 
158 
159             
原文地址:https://www.cnblogs.com/wally/p/3059095.html