题目链接: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),然后就是二分搜索了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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