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             

 

你可能感兴趣的:(HDU)