• ACwing 861


    给定一个二分图,其中左半部包含n1个点(编号1 - n1),右半部包含n2个点(编号1 - n2),二分图共包含m条边。

    数据保证任意一条边的两个端点都不可能在同一部分中。

    请你求出二分图的最大匹配数。

    二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

    二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

    输入格式

    第一行包含三个整数 n1、 n2 和 m。

    接下来m行,每行包含两个整数u和v,表示左半部点集中的点u和右半部点集中的点v之间存在一条边。

    输出格式

    输出一个整数,表示二分图的最大匹配数。

    数据范围

    1≤n1,n2≤500,
    1≤u≤n1,
    1≤v≤n2,
    1≤m≤105

    输入样例:

    2 2 4
    1 1
    1 2
    2 1
    2 2

    输出样例:

    2

    题目大意:

    给出一个二分图,输入n1 n2 m 表示一个集合有n1 个点,另一个集合有 n2 个点,输入 m 条边,输出二分图的最大匹配对数,所谓匹配就是两个集合一对一,不存在一对多或多对一,且一个点只能用一次。

    解题思路:

    这道题用匈牙利算法去解二分图的最大匹配问题,先用邻接表存图,匹配时遍历 n1 中的每一个点,让这个点去和 n2 中的点去匹配,如果匹配成功了就ans ++ 。
    这里要说明的是:看该点 x 是否能和 n2 中的点匹配上,我们用邻接表存图,去遍历点 x 的所有边集,对于每一个和 x 连通的 j ,如果 j 没有尝试过,则尝试和 j 去匹配,这里用一个match数组记录n2 中的点和 n1 中的哪个点匹配了,如果match[j] == 0 则说明没有匹配过,直接令match[j] = x,返回true匹配成功,如果match[j]非空,则尝试让 match[j] (代表 n1 中和 n2 的 j 点匹配成功的点)重新匹配以空出 j ,如果能重新匹配则令match[j] = x,返回true匹配成功,如果遍历完没有找到匹配的则false

    Code:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    const int N = 550, M = 1e5 + 50;
    
    int h[N], e[M], ne[M], idx = 0;
    int match[N];
    bool vis[N];
    int n1, n2, m;
    
    void add(int a, int b)
    {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    bool find(int x)
    {
        for (int i = h[x]; ~i; i = ne[i])
        {
            int j = e[i];
            if (!vis[j])
            {
                vis[j] = true;
                if (!match[j] || find(match[j]))
                {
                    match[j] = x;
                    return true;
                }
            }
        }
        
        return false;
    }
    
    int main()
    {
        cin >> n1 >> n2 >> m;
        memset(h, -1, sizeof h);
        
        while (m--)
        {
            int a, b;
            cin >> a >> b;
            add(a, b);//我们只存从n1 到 n2 的,所以即使是无向边也只存一次
        }
        
        int ans = 0;
        for (int i = 1; i <= n1; i ++)//对 n1 中的每一个点进行匹配
        {
            memset(vis, false, sizeof vis);//每次初始化 n2 ,表示 n2 中的每一个可能匹配的点都没有浏览过
            if (find(i)) ans ++;
        }
        
        cout << ans << endl;
        
        return 0;
    }
    
  • 相关阅读:
    2018-2019-2 网络对抗技术 20165317 Exp5 MSF基础应用
    2018-2019-2 网络对抗技术 20165317 Exp4 恶意代码分析
    2018-2019-2 网络对抗技术 20165317 Exp3 免杀原理与实践
    2018-2019-2 网络对抗技术 20165317 Exp2 后门原理与实践
    2018-2019-2 20165317《网络对抗技术》Exp1 PC平台逆向破解
    2018-2019-2 《网络对抗技术》Exp0 Kali安装 Week1 20165317
    2018-2019-2 20165308《网络对抗技术》Exp9 Web安全基础
    2018-2019-2 网络对抗技术 20165308 Exp 8 Web基础
    2018-2019-2 20165308网络对抗技术 Exp6:信息收集与漏洞扫描
    20165308『网络对抗技术』Exp5 MSF基础应用
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294138.html
Copyright © 2020-2023  润新知