二分图最大匹配——匈牙利算法(附板子)

二分图定义:

将图的点分成两个集合,且每个集合内部不能有边相连,图上每条边的两端都分别来自两个集合,总之,就是每条边的两端不会来自同一个集合。这样的图称之为二分图。

如何判断二分图?

  • 首先,判断该图点集能否被分成两个独立的点集。
  • 图G为二分图的充要条件是G中的每一个环的长度都是偶数,即不存在奇数环。

二分图最大匹配:

  • 给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配.
  • 选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)

匈牙利算法:

  • 匈牙利算法主要解决图的最大匹配数和最小覆盖数的问题。
  • 二分图的最大匹配数等于最小覆盖数!

算法过程图:

将二分图转换为如下图:相当于左边一栏都是男孩子,右边一栏都是女孩子,现在安排两个人结婚,当然同性人不能结婚,问最多能安排多少组婚礼。

现在从B1开始选,他选择了G1,G1的原配是B1。

 

轮到B2了, 他也想选G1但是G1已经名花有主了,她的原配B1只能考虑成全B2而选择了G3,G1的原配变成了B2,G3的原配是B1

轮到B3选择了,他选G1,但是G1原配是B2,B2如果不选G1的话,那么只能去选G3,但是G3原配是B1呀,B1没有可供选择的备胎了,所以B1果断拒绝成全他人,这样的话B3也没有可供选择的备胎了,所以B3还是单身狗。QAQ

轮到B4做选择了,他选的G4并没有原配,那么就恭喜B4,他俩牵手成功!所以最大匹配就是3

以上就是匈牙利算法全过程!!

附上例题以及板子代码:

hdu 2063  过山车(板子题)

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define sc(a) scanf("%d", &a)
#define sc2(a, b) scanf("%d%d", &a, &b)
#define ss(a) scanf("%s", a)
#define mem(a, b) memset(a, b, sizeof(a))
#define PII pair<int, int>
using namespace std;
const int N = 505;
vector<int> g[N]; //如果允许出现重边的话,那么可以直接用邻接矩阵g[u][v]做标记较好,否则可以动态数组
int pre[N], uN, vN;
bool used[N]; //标记是否配对
bool dfs(int u)
{
    for (auto v : g[u])
    {
        if (!used[v])
        {
            used[v] = true;
            if (pre[v] == -1 || dfs(pre[v]))
            {
                pre[v] = u;  //标记原配
                return true; //如果女主没有原配或者女主的原配有符合条件的备胎,那么他俩可以组合
            }
        }
    }
    return false; //如果他没有可供选择的备胎了,那么他就变成单身狗了,QAQ
}
int solve()
{
    int ans = 0;
    mem(pre, -1); //原配初始值为-1
    for (int u = 1; u <= uN; u++)
    {
        mem(used, false);
        if (dfs(u)) //如果找到原配了,那么组合加1
            ans++;
    }
    return ans;
}
int main()
{
    int k;
    while (~sc(k) && k)
    {
        sc2(uN, vN);                  //两个集合的大小
        for (int i = 1; i <= uN; i++) //动态数组清空
            g[i].clear();
        for (int i = 1; i <= k; i++)
        { //动态数组建边
            int u, v;
            sc2(u, v);
            g[u].push_back(v);
        }
        cout << solve() << endl;
    }
    system("pause");
    return 0;
}

洛谷 P3386 【模板】二分图最大匹配

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define sc(a) scanf("%d", &a)
#define sc2(a, b) scanf("%d%d", &a, &b)
#define ss(a) scanf("%s", a)
#define mem(a, b) memset(a, b, sizeof(a))
#define PII pair<int, int>
using namespace std;
const int N = 505;
int pre[N], g[N][N], vN, uN;
bool used[N];
bool dfs(int u)
{
    for (int v = 1; v <= vN; v++)
    {
        if (g[u][v] && !used[v])
        {
            used[v] = true;
            if (pre[v] == -1 || dfs(pre[v]))
            {
                pre[v] = u;
                return true;
            }
        }
    }
    return false;
}
int solve()
{
    int ans = 0;
    mem(pre, -1);
    for (int u = 1; u <= uN; u++)
    {
        mem(used, false);
        if (dfs(u))
            ans++;
    }
    return ans;
}
int main()
{
    int k;
    sc2(uN, vN);
    sc(k);
    while (k--)
    {
        int u, v;
        sc2(u, v);
        g[u][v] = 1;
    }
    cout << solve() << endl;
    system("pause");
    return 0;
}

 持续更新中......

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/107720845
今日推荐