匈牙利算法。复杂度为O(mn)。
对每个点都找以它为起点的增广路,当找到增广路后,匹配数必定加1。
#include <stdio.h> #include <string.h> const int N = 105; const int M = 10005; struct Vertex { int head; }V[N]; struct Edge { int v,next; }E[M]; int top,match[N]; bool used[N]; void Init() { top = 0; memset(V,-1,sizeof(V)); } void Add_Edge(int u,int v) { E[top].v = v; E[top].next = V[u].head; V[u].head = top++; } bool dfs(int u) { for(int i=V[u].head;~i;i=E[i].next) { int v = E[i].v; if(!used[v]) { used[v] = true; if(!match[v] || dfs(match[v])) { match[v] = u; return true; } } } return false; } int maxMatch(int n) { int ans = 0; memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) { memset(used,false,sizeof(used)); if(dfs(i)) ++ans; } return ans; }
下面介绍几种应用到二分图匹配的常见问题模型。
为了方便,以下我们都设要选取的点集为 U ,总点集为 V,最大匹配的边集为 M。
1、最小顶点覆盖:在二分图中选取最少的点覆盖所有的边(边被覆盖是指被至少选取一个端点)。
1)|U| <= |M|。只需要去覆盖 M 中每条边即可。如果选完后不能覆盖所有的边,则把那条边加入 M,会使 M 变大,与 M 最大矛盾。
2)|U| >= |M|。由于 M 中任意两条边都无公共点,所以覆盖这些边至少就需要 |M| 个点。
2、最大独立集:在二分图中选取最多的点,使这些点互不相连。
1)|U| <= |V| - |M|。M 中每条边最多只能选取一个点放入 U,即至少有一个点不在 U 里面,从而一共至少 |M| 个点不在 U 里面。
2)|U| >= |V| - |M|。首先,不在 M 中出现的点一定都能放入 U,假如不能放,那么将导致相连的这条边加入 M,同样会使 M 变大,与 M 最大矛盾。
然后,M 中每条边至少选取一个点可以放入 U。如果两个点都不能放,那么肯定会出现一条增广路,使 M 变大,与 M 最大矛盾。
3、最小路径覆盖。