题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081
题意:有2n个小孩(n个男孩,n个女孩)在玩一个游戏。每一轮游戏女孩会挑选她喜欢的男生作为伴侣,并且规定她的女性朋友喜欢的男孩也是她喜欢并可以挑选的。而且她们遵循朋友的朋友也是朋友的原则。问最多能进行几轮游戏。
思路:
首先要得到每个女孩可以挑选的男孩范围,这个可以借助并查集来实现。将互为朋友的女生全部连在一起,视为一个头节点,然后这些女生喜欢的男生可以用一个vector记录在头节点下面。
然后建立一个超级源点与女生相连,建立一个超级汇点与男生相连,男女之间存在关系的建立容量为1的边。
如果进行了n轮游戏,合法的情况下最大流一定为 n * x。
然后跑一个dinic即可得出答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i(a); i <= (b); ++i)
#define dec(i, a, b) for(int i(a); i >= (b); --i)
#define MP make_pair
const int INF = 1e9 + 7;
const int N = 100000 + 10;
const int M = 10000 + 10;
const int Q = 1000 + 10;
const int A = 300 + 10;
int G[A][A],father[A],girl[A*A],boy[A*A],dis[A];
vector<int> match[A];
int n,st,ed;
void init(void){
rep(i,0,n){
father[i] = i;
match[i].clear();
}
}
int find(int x){
if(x != father[x])
father[x] = find(father[x]);
return father[x];
}
void build_G(int flow){
memset(G,0,sizeof(G));
rep(i,1,n){
G[st][i] = flow;
G[i+n][ed] = flow;
int u = find(i);
int len = match[u].size() - 1;
rep(j,0,len){
G[i][match[u][j]] = 1;
}
}
}
void merge(int x,int y){
x = find(x);
y = find(y);
if(x != y){
father[y] = x;
}
}
bool bfs(void){
queue<int> que;
memset(dis,0,sizeof(dis));
dis[st] = 1;
que.push(st);
while(que.size()){
int u = que.front();
que.pop();
rep(v,1,ed){
if(G[u][v] && dis[v] == 0){
dis[v] = dis[u] + 1;
if(v == ed) return true;
que.push(v);
}
}
}
return false;
}
int dfs(int u,int low){
int uflow = 0;
if(u == ed) return low;
rep(v,1,ed){
if(dis[v] == dis[u] + 1 && G[u][v]){
int flow = min(low-uflow, G[u][v]);
flow = dfs(v,flow);
G[u][v] -= flow;
G[v][u] += flow;
uflow += flow;
if(uflow == low) break;
}
}
if(uflow == 0) dis[u] = 0;
return uflow;
}
int dinic(void){
int ans = 0;
while(bfs()){
ans += dfs(st,INF);
}
return ans;
}
void solve(void){
int left = 0,right = ed;
int ans=0;
while(left <= right){
int mid = (left + right) >> 1;
build_G(mid);
int tem = dinic();
if(tem == mid*n){
left = mid + 1;
ans = mid;
}
else
right = mid - 1;
}
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int m,f;
scanf("%d%d%d",&n,&m,&f);
init();
rep(i,1,m) scanf("%d%d",&girl[i],&boy[i]);
rep(i,1,f){
int x,y;
scanf("%d%d",&x,&y);
merge(x,y);
}
rep(i,1,m){
int u = find(girl[i]);
match[u].push_back(boy[i]+n);
}
st = 2*n + 1,ed = st + 1;
solve();
}
return 0;
}