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

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

1:概念:

​ 匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点;

​ 最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配;

​ 完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配;

2:原理:

​ 先将图化为左右两边(必须为二分图)

​ 左侧:n, 右侧:m

​ 定义数组:used[]: 标记数组

​ s[]: 每个右点与之匹配的左点编号,开始时清零

​ 遍历左边各点:1:每次将used标记数组清零;

​ 2: find()成立,找到,即可将sum++;

//整体
for(int i=1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(find(i)) sum++;
	}

下面是寻找与之匹配的各点:(核心算法:dfs)

​ 方式:对能够到达的右点查找:(并且是没查找过的)

​ 如果该右点没有匹配过,或者 匹配过但是递归回去可以将原本匹配好的左点改为另一个右点对应,则可以将本左点与该右点匹配

​ 否则继续寻找,或false

//邻接矩阵版本:
bool find(int i){
	for(int j=1;j<=m;j++){
		if(used[j]==0 && g[i][j]){
			used[j] = 1;
			if(s[j]==0 || find(s[j])){
				s[j] = i;
				return true;
			}
		}
	}
	return false;
}
//邻接表版本:
bool find(int i){
	for(int j=0; j<g[i].size();j++){
		int x = g[i][j];
		if(used[x]==0){
			used[x] = 1;
			if(s[x]==0 || find(s[x])){
				s[j] = i;
				return true;
			}
		}
	}
	return false;
}

3:题目

模板题:洛谷3386

//邻接表做法
#include <bits/stdc++.h>
#define maxn 550
using namespace std;

int n,m,e;
int used[maxn],s[maxn];
vector<int> g[maxn];

bool check(int a,int b){
	for(int i=0;i<g[a].size();i++){
		if(g[a][i] == b) return false;
	}
	return true;
}

bool find(int i){
	for(int j=0;j<g[i].size();j++){
		int x = g[i][j];
		if(used[x]==0){
			used[x] = 1;
			if(s[x]==0 || find(s[x])){
				s[x] = i;
				return true;
			}
		}
	}
	return false;
}

int main(){
	cin>>n>>m>>e;
	while(e--){
		int a,b;
		cin>>a>>b;
		if(check(a,b))
			g[a].push_back(b);
	}
	
	int sum = 0;
	for(int i=1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(find(i)) sum++;
	}
	cout<<sum<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值