二分图之最大匹配匈牙利算法

匹配是一个边的集合,集合中的任意两条边都没有公共顶点。

而最大匹配是指一个图的所有匹配中,所含边数最多的匹配称为最大匹配。

求解最大匹配通常使用匈牙利算法。介绍一下匈牙利算法中用到的一些概念。

交替路:

从一个未匹配点出发,经非匹配边、匹配边、非匹配边、...形成的路径叫做交替路。

增广路:

从一个未匹配点出发,走交替路,如果经过另一个未匹配点(注意是另一个),则这条路称为增广路。


而对于每一条增广路来说,非匹配边总是要比匹配边大1,所以我们交换一下匹配边和非匹配边就可以增加匹配的边数。

匈牙利算法就是通过不断寻找增广路来改进匹配知道没有增广路的时候达到最大匹配。

下面代码中详细介绍了匈牙利算法的过程


#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

vector<int>g[1005];//记录图
bool used[1005];//used[u]标记u是否在交替路中
int matched[1005];//matched[u]记录与u的匹配,若没有为-1

void add(int u, int v){
	g[u].push_back(v);
}

bool dfs(int u){//dfs函数用于返回是否能找到从u出发的一条增广路
	//访问所有与u相邻的结点
	for (int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if (!used[v]){//若相邻结点v不在交替路中
			used[v] = true;//把v放到交替路中
			//如果v没有匹配,则找到了增广路,并让u与v匹配
			//如果v匹配了,并且我们从v匹配的顶点matched[v]出发找到一条增广路,那么我们就可以让u跟v匹配
			if (matched[v] == -1 || dfs(matched[v])){
				matched[u] = v;
				matched[v] = u;
				return true;
			}
		}
	}
	return false;
}

int hungarian(int n){//返回最大匹配数
	int ret = 0;//ret为最大匹配数
	memset(matched, -1, sizeof matched);//初始化所有点都未匹配
	for (int i = 1; i <= n; i++){
		//遍历所有节点,对于未匹配的结点寻找是否存在增广路
		if (matched[i] == -1){
			//初始化used数组为false,因为交替路是相对于特定的i来说的,所以一定要初始化
			memset(used, false, sizeof used);
			//这里不用标记,因为used表示的是与节点i不在同一集合中的交替路中的节点
			//used[i] = true;
			//若存在增广路,最大匹配数+1
			if (dfs(i))ret++;
		}
	}
	return ret;
}

int main(){
	//freopen("in.txt", "r", stdin);
	int n, m; scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++){
		int u, v; scanf("%d %d", &u, &v);
		add(u, v);
		add(v, u);
	}
	int ans = hungarian(n);
	printf("%d\n", ans);
	return 0;
}


要注意对于二分图我们可以只遍历其中的一个点集从而提高算法的效率。


匈牙利算法还可以求最小点覆盖数、最大独立数。

最小点覆盖数:选取最少的点,使得任意一条边至少有一条边被选择。

最大独立数:选最多的点,使得任意两点不相连


König定理可知最小点覆盖数 = 二分图最大匹配
最大独立数 = 总点数 - 二分图最大匹配

结论记住就好了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值