也叫”月老”算法。用于计算一个给定的二分图的最大匹配。
基本概念:
二分图的匹配:给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。 二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
匹配:选边的数量且选择的所有边没有重复节点。
最大匹配:边数最多的匹配
匹配点:指选择的边的端点
增广路径:从一个非匹配点出发,先走非匹配边,再走非匹配边,以此类推,最终走到某个非匹配点的路径就是一个增广路径。
模板
861. 二分图的最大匹配
给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。
数据保证任意一条边的两个端点都不可能在同一部分中。
请你求出二分图的最大匹配数。
输入格式
第一行包含三个整数 n1、 n2 和 m。
接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v 之间存在一条边。
输出格式
输出一个整数,表示二分图的最大匹配数。
数据范围
1≤n1,n2≤500
1≤u≤n1
1≤v≤n2
1≤m≤105
输入样例:
2 2 4
1 1
1 2
2 1
2 2
输出样例:
2
思路:
遍历左半部分每个点i
,为其在右半部分寻一个对象(即遍历i
的每条边)。
如果i
中意的对象没有被选,那就将其匹配给i
如果i
中意的对象已经被选,尝试让其原配重新选一个
它的原配能再选一个其他的,它就与i
匹配成功
它的原配不能再选其它的了,它与i
匹配失败,i
继续尝试其它的
如果i
选无可选,匹配失败,i
打光棍吧
时间复杂度:O(nm)
import java.util.*;
public class Main {
static final int N = 510, M = 100010;
static int[] h = new int[N], e = new int[M], ne = new int[M];
static int idx;
static int[] match = new int[N];
static boolean[] st = new boolean[N];
static int n1, n2, m;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n1 = sc.nextInt();
n2 = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
for (int i = 0; i < m; i++) {
int a = sc.nextInt(), b = sc.nextInt();
add(a, b);
}
int cnt = 0;
for (int i = 1; i <= n1; i++) {
Arrays.fill(st, false);
if (find(i))
cnt++;
}
System.out.println(cnt);
}
static void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
static boolean find(int u) {
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true;
if (match[j] == 0 || find(match[j])) {
match[j] = u;
return true;
}
}
}
return false;
}
}