二分图匹配:匈牙利算法
二分图匹配
二分图
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;
}

浙公网安备 33010602011771号