【HDU】3081 Marriage Match II

本文介绍了一道关于二分图并查集的经典算法题MarriageMatchII,通过并查集处理女生的朋友集合,并求解最大匹配来确定最多可以进行的游戏轮数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值