HDU-3081-Marriage Match II【并查集】【二分图匹配】


HDU-3081-Marriage Match II


Problem Description
Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the game of playing house we used to play when we are kids. What a happy time as so many friends playing together. And it is normal that a fight or a quarrel breaks out, but we will still play together after that, because we are kids.
Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend.
Once every girl finds their boyfriends they will start a new round of this game—marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on.
Now, here is the question for you, how many rounds can these 2n kids totally play this game?

Input
There are several test cases. First is a integer T, means the number of test cases.
Each test case starts with three integer n, m and f in a line (3 < = n < = 100,0 < m < n*n,0 < = f < n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n).
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other.
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends.

Output
For each case, output a number in one line. The maximal number of Marriage Match the children can play.

Sample Input
1
4 5 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3

Sample Output
2

题目链接:HDU-3081

题目大意:有编号为1~n的女生和1~n的男生配对

首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架

然后输入f组,c,d表示编号为c的女生和编号为d的女生是朋友

进行配对的要求满足其一即可。
1.a女生没有和b男生吵过架
2.a女生的朋友和b男生没有吵过架

每进行一轮之后重新配对,配过得一对不可再配,问最多能进行几轮。

题目思路:

第一步:要求2可以处理一下变成要求1.这里就需要用到并查集啦(刚开始用dfs处理,然而超内存了)

1.两个女生是朋友就用并查集合并
2.遍历,如果两个女生a,b父节点一样,那么b所能配对的男生a也能配对

for (int i = 1; i <= n; i++)
{
    int t = getfather(i);//得到编号为i这个女生的父节点

    for (int j = 1; j <= n; j++)
    {
        if (i != j && getfather(j) == t)  //如果两个女生是朋友
        {
            for (int k = 1; k <= n; k++)  //那么j的朋友k,也是i的朋友
            {
                if (g[j][k]) g[i][k] = 1;
            }
        }
    }
}

第二步:二分图匹配,套用模板就好啦。

以下是代码:

//
//  HDU-3081.cpp
//  HDU
//
//  Created by pro on 16/5/20.
//  Copyright (c) 2016年 loy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include<iomanip>
using namespace std;
int g[105][105];
#define MAXN 105
int fa[MAXN] = {0};
int vis[105];
int link[105];  //编号为i的女生对应的男生编号
int n,m,f,ans = 0;
void initialise(int n)          //初始化
{
    for (int i = 1; i <= n; i++)
        fa[i] = i;
}
int getfather(int v)            //父节点
{
    return (fa[v] == v) ? v : fa[v] = getfather(fa[v]);
}
void merge(int x,int y)         //合并
{
    x = getfather(x);
    y = getfather(y);
    if (x != y)
        fa[x] = y;
}

bool dfs(int u) {
    for (int v = 1; v <= n; v++) {
        if (!vis[v] && g[u][v]) {
            vis[v] = 1;
            if (!link[v] || dfs(link[v])) {
                link[v] = u;
                return true;
            }
        }
    }
    return false;
}
void solve()
{
    while(1)
    {
       // cout << ans << endl;
        memset(link,0,sizeof(link));
        int cnt = 0;
        for (int i = 1; i <= n; i++)
        {
            memset(vis,0,sizeof(vis));
            if (dfs(i)) cnt++;  //如果找到了能配对的
        }
        if (cnt == n) //如果全部配对成功
        {
            ans++;
            for (int i = 1; i <= n; i++)
            {
                g[link[i]][i] = 0;   //编号为i以及对应的女生不能再连
            }
        }
        else
        {
            break;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int u,v;
        scanf("%d%d%d",&n,&m,&f);
        memset(g,0,sizeof(g));
        initialise(n);
        ans = 0;
        for (int i = 0; i < m; i++)
        {
            scanf("%d%d",&u,&v);
            g[u][v] = 1;
        }
        for (int i = 0; i < f; i++)
        {
            scanf("%d%d",&u,&v);
            merge(u,v);
        }
        for (int i = 1; i <= n; i++)
        {
            int t = getfather(i);//得到编号为i这个女生的父节点

            for (int j = 1; j <= n; j++)
            {
                if (i != j && getfather(j) == t)  //如果两个女生是朋友
                {
                    for (int k = 1; k <= n; k++)  //那么j的朋友k,也是i的朋友
                    {
                        if (g[j][k]) g[i][k] = 1;
                    }
                }
            }
        }
        solve();
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值