二分图定义:
将图的点分成两个集合,且每个集合内部不能有边相连,图上每条边的两端都分别来自两个集合,总之,就是每条边的两端不会来自同一个集合。这样的图称之为二分图。
如何判断二分图?
- 首先,判断该图点集能否被分成两个独立的点集。
- 图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;
}
持续更新中......