1 条题解

  • 0
    @ 2025-4-13 12:11:38

    二分图最大匹配题解

    题目概述

    这道题目要求我们计算一个二分图的最大匹配边数。二分图是指顶点可以分成两个不相交的集合,使得每条边的两个端点分别属于这两个集合。最大匹配是指在二分图中找到尽可能多的边,使得这些边没有共同的顶点。

    算法思路

    本题采用匈牙利算法来解决二分图最大匹配问题。匈牙利算法的基本思想是通过不断寻找增广路径来增加匹配的边数。

    关键步骤

    图的构建:使用邻接表存储二分图的边关系。

    匹配过程:对于左部的每一个顶点,尝试在右部找到一个未匹配的顶点或者能够"腾出"位置的顶点。

    增广路径:通过深度优先搜索(DFS)寻找增广路径,如果找到则增加匹配数。

    代码解析

    #include <bits/stdc++.h>
    using namespace std;
    
    int n, m, k, a, b, ans;
    struct node {
        int v, ne; // v表示边的终点,ne表示下一条边的索引
    }e[100005];
    int h[100005], idx; // h数组存储每个顶点的第一条边,idx是边的计数器
    int vis[100005], match[100005]; // vis记录访问状态,match记录右部顶点的匹配
    
    // 添加边
    void add(int a, int b) {
        e[++idx] = {b, h[a]};
        h[a] = idx;
    }
    
    // 匈牙利算法核心DFS函数
    bool dfs(int u) {
        for (int i = h[u]; i; i = e[i].ne) {
            int v = e[i].v;
            if (vis[v]) continue; // 如果已经访问过则跳过
            vis[v] = 1;
            // 如果右部顶点未匹配,或者可以找到增广路径
            if (!match[v] || dfs(match[v])) {
                match[v] = u; // 更新匹配
                return true;
            }
        }
        return false;
    }
    
    int main() {
        cin >> n >> m >> k;
        for (int i = 0; i < k; i++) {
            cin >> a >> b;
            add(a, b); // 添加边
        }
        
        // 对每个左部顶点尝试匹配
        for (int i = 1; i <= n; i++) {
            memset(vis, 0, sizeof(vis)); // 每次匹配前重置访问状态
            if (dfs(i)) ans++; // 如果找到匹配则增加计数
        }
        
        cout << ans << endl;
        return 0;
    }
    

    复杂度分析

    时间复杂度:O(n*e),其中n是左部顶点数,e是边数。对于每个左部顶点,最坏情况下需要遍历所有边。

    空间复杂度:O(n+m+e),用于存储图结构和匹配信息。

    优化建议

    对于大规模数据,可以考虑更高效的算法如Hopcroft-Karp算法,其时间复杂度为O(e√n)。

    可以使用更高效的图表示方法,如前向星等。

    总结

    匈牙利算法是解决二分图匹配问题的经典算法,虽然在最坏情况下时间复杂度较高,但对于题目给定的数据规模(1≤n,m≤500)是完全可行的。理解并掌握这一算法对于解决图论中的匹配问题非常重要

    信息

    ID
    7416
    时间
    1000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    58
    已通过
    12
    上传者