Marriage Match II
题目链接
题目大意
n个女生n个男生玩过家家~满足如下2个条件即可组成一对:
- 女生a没和男生b吵过架
- 女生a的朋友c没和男生b吵过架
每个人都配对之后就继续玩下一轮,但是下一轮中每个人都必须选择一个另外的人配对,现在问最多玩多少轮。
题解
二分图 并查集
我们可以看到如果a的朋友b能和c配对,那么a也能和c配对,所以我们先用并查集处理出女生的朋友集合,然后对于每两个女生和男生的情况处理出所有的边。最后对整个图求最大匹配,当最大匹配与n相等的时候,先删去当前匹配边,再继续求最大匹配,当某个时刻最大匹配和n不相等,此时循环的次数就是答案。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int T,n,m,f,b,a;
int g[105][105],link[105],father[105];
bool vis[105];
int getfather(int k)
{
if (father[k]==k) return k;
return father[k]=getfather(father[k]);
}
bool dfs(int u)
{
for (int i=1;i<=n;i++) if (!vis[i] && g[u][i])
{
vis[i]=1;
if (!link[i] || dfs(link[i]))
{
link[i]=u;
return 1;
}
}
return 0;
}
int solve()
{
int ans=0;
memset(link,0,sizeof(link));
for (int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if (dfs(i)) ans++;
}
for (int i=1;i<=n;i++) if (link[i]) g[link[i]][i]=0;
return ans;
}
int main()
{
scanf("%d",&T);
while (T--)
{
for (int i=0;i<105;i++) father[i]=i;
memset(g,0,sizeof(g));
scanf("%d%d%d",&n,&m,&f);
for (int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
g[a][b]=1;
}
for (int i=0;i<f;i++)
{
scanf("%d%d",&a,&b);
int fa,fb;
fa=getfather(a); fb=getfather(b);
if (fa!=fb) father[fa]=fb;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
int f1,f2;
f1=getfather(i);
f2=getfather(j);
if (f1==f2) for (int k=1;k<=n;k++) if (g[i][k]) g[j][k]=1;
}
int ans=0;
while (solve()==n) ans++;
printf("%d\n",ans);
}
return 0;
}