二分图匹配:匈牙利算法

二分图匹配

二分图

1.1 定义

二分图,又称二部图,是一类结构特殊的图.它的顶点集可以划分为两个互不相交的子集,使得图中的每条边都连接这两个集合之间的一对点,而不会连接同一集合内部的点。

1.2 判定

判定一个图是否是二分图,可以用 DFS/BFS 染色法:

从任意点出发,将其染成黑色,相邻点染成白色,再相邻的染成黑色……如果染色过程中出现相邻点颜色相同的情况,则说明存在奇环,图不是二分图。

二分图匹配

2.1 定义

在图论中,匹配(Matching)是指图中没有公共端点的一组边的集合。

也就是说,匹配中的任意两条边不能共享同一个顶点。一个顶点最多只能与一条匹配边相连。

二分图匹配,就是在二分图中寻找一个匹配。由于二分图特殊的结构,匹配问题有更高效的解法。

2.2 二分图最大匹配

二分图最大匹配,就是在二分图中找到边数最多的匹配。
匈牙利算法枚举左侧的每一个点,尝试为它寻找一个匹配。如果当前尝试匹配的右侧点已被占用,就递归地尝试让占用者"让座"——去寻找另一个匹配。如果最终能让所有人都满意,匹配数+1。
增广路:增广路(Augmenting Path)是匈牙利算法最核心的概念。

定义:从未匹配的左部点出发,依次经过「非匹配边 → 匹配边 → 非匹配边 → …」最终到达一个未匹配的右部点的路径。

简单说,增广路就是一条起点和终点都未匹配,且路径上的边交替出现的路径。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 150;
int n, m, vis[N], p[N];
int idx, h[N], e[100050], nxt[100050];
void add(int u, int v){
	nxt[++idx] = h[u];
	h[u] = idx;
	e[idx] = v;
}
bool dfs(int u){
	for(int i = h[u]; i; i = nxt[i]){
		int v = e[i];
		if(vis[v]) continue;
		vis[v] = 1;
		if(!p[v] || dfs(p[v])){
			p[v] = u;
			return 1;
		}
	}
	return 0;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> m >> n;
	while(1){
		int u, v;
		cin >> u >> v;
		if(u == -1) break;
		add(u, v);
	}
	int res = 0;
	for(int i = 1; i <= m; i++){
		memset(vis, 0, sizeof vis);
		if(dfs(i)) res++;
	}
	cout << res << '\n';
	for(int i = m+1; i <= n; i++) if(p[i]) cout << p[i] << ' ' << i << '\n'; 
	return 0;
}
posted @ 2026-08-19 14:05  宰杀方向盘  阅读(7)  评论(0)    收藏  举报