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

一直没有学习匈牙利算法,因为网络流实现匹配的功能已经足够强大了。

但今天这道题【BZOJ1191】用网络流实在难以解决动态匹配,而鉴于匈牙利算法实现的代码复杂度极小,所以今天学习一下。


匈牙利算法用于解决二分图匹配问题,主要思想是增广路,对于当前左点u,若能找到一个相连的未匹配的右点v,则直接匹配,否则进行尝试更改其他已匹配的右点匹配的左点的匹配对象【递归】,若成功则匹配成功


二分图匹配问题还有很多变式:

最小点覆盖集 = 最大点独立集 = 最大匹配

最小路径覆盖数 = 点数 - 最大匹配


上题:

BZOJ1191

大意:二分图匹配= =

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 1005,maxm = 100005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1;char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
	return out * flag;
}
int n,m,lk[maxn],vis[maxn];
int head[maxn],nedge = 0;
struct EDGE{int to,next;}edge[maxm];
inline void build(int u,int v){
	edge[nedge] = (EDGE){v,head[u]};
	head[u] = nedge++;
}
bool find(int u){
	int to;
	Redge(u) if (!vis[to = edge[k].to]){
		vis[to] = true;
		if (!lk[to] || find(lk[to])){
			lk[to] = u;
			return true;
		}
	}
	return false;
}
int main()
{
	fill(head,head + maxn,-1);
	int ans = 0;
	n = read(); m = read();
	REP(i,m) build(i,read()),build(i,read());
	REP(i,m){
		memset(vis,0,sizeof(vis));
		if (find(i)) ans++;
		else break;
	}
	cout<<ans<<endl;
	return 0;
}


原文地址:https://www.cnblogs.com/Mychael/p/8282825.html