二分图最大匹配(匈牙利算法)——啊哈!算法笔记

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

最大匹配
    在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配。选择这样的边数最大的子集称为图的最大匹配问题,最大匹配的边数称为最大匹配数.如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。如果在左右两边加上源汇点后,图G等价于一个网络流,最大匹配问题可以转为最大流的问题。解决此问的匈牙利算法的本质就是寻找最大流的增广路径。

匈牙利算法 核心
1.首先从任意一个未被配对的点u开始,从点u的边中任意选一条边开始配对,如果此时点v还没有配对,那么配对成功,此时便找到了一条增广路,如果此时点v已经配对,尝试进行“连锁反应”,如果尝试成功了,则找到了一条增广路,此时需要更新原来的配对关系,这里用一个match数组记录配对关系,比如u和v配对了,记作match[v]=u。配对成功后,把配对数加1,配对的过程使用深度优先搜索实现(dfs)当然广度优先搜索(bfs)也行;
2.如果刚才所选的边配对失败,从点u的边中再选一条边,进行尝试,直到点u配对成功,或者尝试点u所有的边为止
3.接下来对剩下的没有被配对的点一一进行配对,直到所有的点都尝试完毕,找不到新的增广路为止
4.输出配对数 

时间复杂度O(NM)

代码如下:

时间复杂度O(NM)

#include
#include
using namespace std;

int e[101][101];
int match[101];
int book[101];
int n, m;

int dfs(int u)
{
	int i;
	for (i = 1; i <= n; i++) {
		if (book[i] == 0 && e[u][i] == 1) {
			book[i] = 1;//标记点i已经走过 
						//如果点i未被配对或者找到了新的配对 
			if (match[i] == 0 || dfs(match[i])) {
				//更新配对关系 
				match[i] = u;
				return 1;
			}
		}
	}
	return 0;
}

int main()
{
	int i, j, t1, t2, sum = 0;
	scanf("%d%d", &n, &m);//n个点m个边
	for (i = 1; i <= m; i++) {
		scanf("%d%d", &t1, &t2);//读入边
		e[t1][t2] = 1;
	}
	for (i = 1; i <= n; i++)
		match[i] = 0;
	for (i = 1; i <= n; i++) {
		for (j = 1; j <= n; j++) {
			book[j] = 0;//清空上次搜索时的标记
		}
		if (dfs(i)) {//寻找增广路,如果找到,配对数加1 
			sum++;
		}
	}
	printf("%d", sum);
	return 0;
}

数据:

input:

3 5

1 1

1 2

2 2

2 3

3 1

output:

3

算法例题:http://acm.hdu.edu.cn/showproblem.php?pid=2063

如果不能理解请参考这位大佬的博客,上边有图解可能更清晰:https://blog.csdn.net/dark_scope/article/details/8880547

 

你可能感兴趣的:(二分图最大匹配(匈牙利算法)——啊哈!算法笔记)