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

二分图的定义:如果一个图的所有顶点可以被分为X和Y两个集合,并且所有边的两个顶点恰好一个属于集合X,另一个属于集合Y,即每个集合内的顶点没有边相连,那么此图就是二分图。



增广路:增广路的本质就是一条路径的起点和终点都是未被配对的点。

如果找到一条增广路,那么配对数将会加1.


寻找一个点配对的基本思路:

1.从点u开始,从点u引出的边中任意选一条边(u-v)开始配对。如果此时v还没有被配对,则配对成功,找到一条增广路。如果点v已被配对,就尝试进行“连锁反应”,如果尝试成功,则找到一条增广路,并更新配对关系。

2.如果刚才所选的边配对失败,就重新选一条边尝试。直到点u配对成功,或者尝试过点u所有的边为止。

#include<iostream>
#include<cstdio>
using namespace std;

int node[50],next[50],root[50],cnt,m,n;
int match[50],book[50];
//match[x]用来存储x配对的对象,book[x]标记x是否已被访问 
int sum;

//二分图都是无向图 
void insert(int u, int v) {
	cnt++;
	node[cnt] = v;
	next[cnt] = root[u];
	root[u] = cnt;
} 
void build() {
	for (int i=1; i<=m; i++) {
		int u,v;
		cin >> u >> v;
		insert(u,v);
		insert(v,u);
	}
}

//寻找一个点的匹配 
bool dfs(int u)
{
	for (int x=root[u]; x!=-1; x=next[x])
		if (!book[node[x]]) {
			book[node[x]] = 1;
			if (match[node[x]] == -1 || dfs(match[node[x]])) {  //一旦发现寻找增广路可行(dfs的值为1),就向前返回修改match数组的值 
				match[node[x]] = u;
				match[u] = node[x];
				return 1;  //找到增广路,返回 1 
			}
		}
	return 0;  //连锁反应失败,返回 0 
}

int main()
{
	cin >> n >> m;
	for (int i=1; i<=m; i++) next[i] = -1;
	for (int i=1; i<=n; i++) root[i] = -1;
	build();
	
	for (int i=1; i<=n; i++) match[i] = -1;
	
	
	for (int i=1; i<=n; i++) {
		for (int j=1; j<=n; j++) book[j] = 0;  //清空上次搜索时的访问标记,只留下match的配对标记。因为如一个点已经选过,可以引发连锁反应。 
		if (dfs(i)) sum++;  //此时sum存储的是前i个点的最大匹配 
		//因为是最大匹配,所以只要找到一条增广路,sum就加1,后面的搜索是寻找有无新的增广路。 
	}
	cout << sum;
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值