题意:有2*n个孩子,n个男孩编号1到n,n个女孩编号1到n。女士优先,所以每一女孩可以先选择没有和她产生过矛盾的男孩来组建一个家庭。除此之外,女孩X还可以选择男孩Z入股女孩X的朋友女孩Y没有和男孩Z发生过矛盾。如果a和b是朋友,b和c是朋友,那么a和c也是朋友。每次女孩们选好了男朋友她们都会进行一轮“婚姻匹配”。每一轮结束后,每个女孩都会在她之前没有选择的男孩里面选择一个新的男朋友,下一轮就又开始了。问总共能玩几轮?
难度:3
题解:二分+并查集+最大流。新增一个附加源s和一个附加汇t,女生向所有和她所在的并查集女生没有矛盾的男生连一条容量为1的边,每次从s向每个女生连容量为mid的边,从每个男生向t连容量为mid的边,二分枚举mid(0<=mid<=n),找到最大的mid满足求得的最大流是mid*n。
难度:3
题解:二分+并查集+最大流。新增一个附加源s和一个附加汇t,女生向所有和她所在的并查集女生没有矛盾的男生连一条容量为1的边,每次从s向每个女生连容量为mid的边,从每个男生向t连容量为mid的边,二分枚举mid(0<=mid<=n),找到最大的mid满足求得的最大流是mid*n。
#include <cstdio>
#include <cstring>
using namespace std;
const int mm=222222;
const int mn=222;
const int oo=1000000000;
int node,src,dest,edge;
int ver[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
inline int min(int a,int b) {
return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest) {
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;i++) head[i]=-1;
edge = 0;
}
inline void addedge(int u,int v,int c) {
ver[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
}
bool Dinic_bfs() {
int i,u,v,l,r=0;
for(i=0;i<node;++i) dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0;l<r;++l)
for(i=head[u=q[l]];i>=0;i=next[i])
if(flow[i]&&dis[v=ver[i]]<0) {
dis[q[r++]=v]=dis[u]+1;
if(v==dest) return 1;
}
return 0;
}
int Dinic_dfs(int u,int exp) {
if(u==dest) return exp;
for(int &i=work[u],v,tmp;i>=0;i=next[i])
if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0) {
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}
return 0;
}
int Dinic_flow() {
int i,ret=0,delta;
while(Dinic_bfs()) {
for(i=0;i<node;++i) work[i]=head[i];
while(delta=Dinic_dfs(src,oo)) ret+=delta;
}
return ret;
}
int fa[mn];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void Union(int x,int y) {
int a = find(x) , b = find(y);
fa[a] = fa[b] = fa[x] = fa[y] = min(a,b);
}
int girl[mn*mn] , boy[mn*mn];
int n,m,f,T;
bool match[111][111];
bool check(int mid) {
prepare(2*n+2,0,2*n+1);
for(int i=1;i<=n;i++) {
addedge(src,i,mid);
addedge(i+n,dest,mid);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(match[find(i)][j])
addedge(i,j+n,1);
if(Dinic_flow() == n*mid) return 1;
return 0;
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&f);
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=0;i<m;i++)
scanf("%d%d",&girl[i],&boy[i]);
for(int i=0;i<f;i++) {
int u,v;
scanf("%d%d",&u,&v);
Union(u,v);
}
memset(match,0,sizeof(match));
for(int i=0;i<m;i++) {
int u=find(girl[i]);
match[u][boy[i]] = 1;
}
int left = 0 , right = n;
int ans = -1;
while(left <= right) {
int mid = (left + right) >> 1;
if(check(mid)) {
ans = mid;
left = mid + 1;
}
else right = mid - 1;
}
printf("%d\n",ans);
}
return 0;
}