二分图匹配

定义

任意两条边都没有公共端点的边的集合称为二分图的一组匹配。 在二分图中包含边数最多的一组匹配被称为是二分图的最大匹配。

增广路

对于任意一组匹配 S S S,属于S的边称为匹配边,不属于S的边称为非匹配边,匹配边的端点被称为匹配点,其他点被称为非匹配点。如果二分图中存在一条连接两个非匹配边的路径,是的非匹配边和匹配边在这条路径上交替出现,那么这条路径被称为增广路。

二分图的一组匹配 S S S是最大匹配当且仅当图中不存在 S S S的增广路

匈牙利算法

匈牙利的过程为在左边先选一个节点 x x x,后找到 x x x的第一条出边所连接的点 y y y ( x , y ) (x,y) (x,y)构成了一组匹配。然后找到左部的第二个节点 x ′ x' x,再找到 x ′ x' x第一条出边所连接的点 y ′ y' y,若 y ′ ≠ y y' \not =y y=y ( x ′ , y ′ ) (x',y') (x,y)构成了一组匹配,否则先将 x x x y y y连的边消除,若 x x x仍有其他出边,则 x x x和该出边所连接的点构成了一组匹配且 x ′ x' x y ′ y' y也构成了匹配。若 x x x无其他出边则 x ′ x' x y ′ y' y构不成匹配,且 x x x y y y仍为一组匹配。

code

#include  

using namespace std; 

const int N = 1e3 + 100; 
const int M = 1e6 + 100; 

template <typename T> inline void read(T &s) {
	s = 0; T w = 1, ch = getchar();
	while(!isdigit(ch)) { if(ch == '-') w = -1; ch = getchar(); }
	while(isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w;
}

int n, m, E, tot; 
int lin[N], match[N]; 
bool vis[N]; 
struct edge {
	int next, to; 
}e[M<<1];

inline void add(int from, int to) {
	e[++tot].to = to; 
	e[tot].next = lin[from]; 
	lin[from] = tot; 
}

bool dfs(int x) {
	for (int i = lin[x]; i; i = e[i].next) {
		int y = e[i].to; 
		if (vis[y]) continue; 
		vis[y] = true; 
		if (!match[y] || dfs(match[y])) {
			match[y] = x; 
			return true; 
		}
	}
	return false; 
}

int main() {
	read(n), read(m), read(E); 
	for (int i = 1; i <= E; ++i) {
		int x, y; 
		read(x), read(y); 
		if (y > m || x > n) continue; 
		add(x, y); 
	}
	int ans = 0; 
	for (int i = 1; i <= n; ++i) {
		memset(vis, false, sizeof(vis)); 
		if (dfs(i)) ++ans; 
	}
	printf("%d\n", ans);
	return 0; 
}

你可能感兴趣的:(题解————题解,图论——图论,图论——二分图)