前言:二分图最大匹配往往用于普通的指派问题中,可转换为最大流问题求解,也可以利用二分图的性质及其边的容量为1的特点,简单的实现二分图的最大匹配算法。
问题模型:有n台计算机和k个任务,每台计算机处理的任务种类不同,问如果给每台计算机分配一个任务,一次最多能处理多少个任务。
分析:该问题可以转化为图论模型来分析。设U为所有计算机顶点的集合,V为所有任务类型的集合,u属于U,v属于V,e=(u,v)表示计算机u能处理任务v,E是所有e的集合。
则G=(U||V, E),且G中满足两两不含公共端点的边的集合的最大值,就是我们所要求的最大任务数即二分图中的最大匹配。如果此问题转为最大流求解,只需增加一个源点s
和汇点t,从源点到所有计算机连一条容量为1的有向边,从所有任务到终点t也连一条容量为1的有向边,再在计算机与所能处理的任务之间连一条容量为1的有向边,时间复杂度同求解最大流的一样。当然,考虑到所有边的容量均为1及二分图的性质,我们还可以简单实现二分图的最大匹配算法,时间复杂度O(VE)。
//二分图最大匹配算法的简单实现
#include <iostream>
#include <vector>
using namespace std;
vector<int> G[1000];
int match[1000];
bool used[1000];
int dfs(int v)
{//通过深搜寻找增广路O(E)
used[v] = 1;
for(int i = 0; i < G[v].size(); ++i)
{
int u = G[v][i], w = match[u];
if(w == -1 || (!used[w] && dfs(w)))
{
match[u] = v;
match[v] = u;
return 1;
}
}
return 0;
}
void solve(int n, int k, int e)
{
int i, j, ans = 0;
memset(match, -1, sizeof(match));
for(i = 0; i < n + k; ++i)
{
if(match[i] != -1)
continue;
memset(used, 0, sizeof(used));
if(dfs(i))
++ans;
}
cout << ans << endl;
}
int main()
{
int n, k, e;
cin >> n >> k >> e;
for(int i = 0; i < e; ++i;)
{
int u, v;
cin >> u >> v;
G[u - 1].push_back(n + v - 1);
G[n + v - 1].push_back(u - 1);
}
solve(n, k, e);
return 0;
}