稍微综合一点的题目。
建图方法:
对每个女孩喜欢的男孩,连一条容量为1的边
若两个女孩a,b是朋友,则对于a连了边的男孩,b也要连边,使用并查集维护
然后二分出游戏进行的回合数p,s -> 每个女孩,容量为p;每个男孩 -> t,容量为p
若最大流 = n * p说明p是可行的,这样就可以得出最多进行的回合数了。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 200 + 10;
const int maxm = maxn * maxn;
const int inf = 0x3f3f3f3f;
struct node
{
int a,b;
}pair[maxm];
int cap[maxn][maxn],pre[maxn],cur[maxn],dis[maxn],gap[maxn];
int f[maxn];
int T,n,m,h;
int s,t,nodenum;
inline int min(int a,int b)
{
return a < b ? a : b;
}
void set_init()
{
for(int i = 1;i <= n;i++)f[i] = i;
}
int find(int x)
{
if(f[x] == x)return x;
f[x] = find(f[x]);
return f[x];
}
bool query(int a,int b)
{
return find(a) == find(b);
}
void set_union(int a,int b)
{
f[find(a)] = find(b);
}
void init()
{
freopen("hdu3081.in","r",stdin);
freopen("hdu3081.out","w",stdout);
}
void build_map()
{
memset(cap,0,sizeof(cap));
for(int i = 1;i <= m;i++)
{
cap[pair[i].a][pair[i].b + n] = 1;
}
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
if(i != j && query(i,j))
{
for(int k = 1;k <= n;k++)
{
if(cap[i][k+n] && !cap[j][k+n])cap[j][k+n] = 1;
if(cap[j][k+n] && !cap[i][k+n])cap[i][k+n] = 1;
}
}
}
}
}
int sap()
{
memset(gap,0,sizeof(gap));
memset(cur,0,sizeof(cur));
memset(dis,0,sizeof(dis));
int u = pre[s] = s,maxflow = 0,aug = inf;
gap[s] = nodenum;
while(dis[s] < nodenum)
{
loop: for(int v = cur[u];v < nodenum;v++)
{
if(cap[u][v] && dis[u] == dis[v] + 1)
{
aug = min(aug,cap[u][v]);
cur[u] = v;
pre[v] = u;
u = v;
if(v == t)
{
maxflow += aug;
for(u = pre[u];v != s;v = u,u = pre[u])
{
cap[u][v] -= aug;
cap[v][u] += aug;
}
aug = inf;
}
goto loop;
}
}
int mind = nodenum;
for(int v = 1;v < nodenum;v++)
{
if(cap[u][v] && (mind > dis[v]))
{
cur[u] = v;
mind = dis[v];
}
}
if((--gap[dis[u]]) == 0)break;
gap[dis[u] = mind + 1]++;
u = pre[u];
}
return maxflow;
}
bool check(int p)
{
build_map();
for(int i = 1;i <= n;i++)cap[s][i] = p;
for(int i = n + 1;i <= 2 * n;i++)cap[i][t] = p;
return sap() == (p * n);
}
void solve()
{
s = 0,t = 2 * n + 1;
nodenum = t + 1;
int l = 0,r = n;
while(l < r)
{
int m = (l + r + 1) >> 1;
if(check(m))l = m;
else r = m - 1;
}
printf("%d\n",l);
}
void readdata()
{
scanf("%d",&T);
while(T--)
{
memset(cap,0,sizeof(cap));
scanf("%d%d%d",&n,&m,&h);
set_init();
for(int i = 1;i <= m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
pair[i].a = a;pair[i].b = b;
}
for(int i = 1;i <= h;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(!query(a,b))set_union(a,b);
}
solve();
}
}
int main()
{
init();
readdata();
return 0;
}