图论·二分图

文章目录

二分图的定义

形式化定义

一个二分图 (又称二部图 ,Bipartite Graph)是一个三元组 G = ( U , V , E ) G = (U, V, E) G=(U,V,E),其中:

  • U U U 和 V V V 是两个非空互不相交 的顶点集合,即 U ∩ V = ∅ U \cap V = \emptyset U∩V=∅
  • E E E 是边的集合
  • 任意一条边 e ∈ E e \in E e∈E 都连接 U U U 中的一个顶点和 V V V 中的一个顶点

等价定义

染色定义:二分图判定法

图 G G G 是二分图,当且仅当它可以用 2种颜色 对顶点进行染色,使得任意一条边的两个端点颜色不同。

用数学语言表达:存在一个函数 c : V → { 0 , 1 } c: V \rightarrow \{0, 1\} c:V→{0,1},使得对于任意边 ( u , v ) ∈ E (u, v) \in E (u,v)∈E,都有 c ( u ) ≠ c ( v ) c(u) \neq c(v) c(u)=c(v)。

奇环定义:由染色定义衍生而来

图 G G G 是二分图,当且仅当它不包含奇环 (奇数长度的环)。

即:对于任意整数 k k k, G G G 中不存在长度为 2 k + 1 2k + 1 2k+1 的环。

特例:自环、重边和孤立点

  • 自环(self-loop)是不允许存在的(因为自环的两个端点在同一个集合中)
  • 重边不影响二分图存在
  • 孤立点可以属于任意一个集合,不影响二分性

完全二分图

一种特殊的二分图称为完全二分图 ,记作 K m , n K_{m, n} Km,n,其中:

  • ∣ U ∣ = m |U| = m ∣U∣=m, ∣ V ∣ = n |V| = n ∣V∣=n
  • U U U 中的每个顶点都与 V V V 中的所有顶点相连
  • 边数 ∣ E ∣ = m × n |E| = m \times n ∣E∣=m×n

二分图的应用

染色法判定二分图

例题

实现

  • 定义一个colors数组记录颜色,对于visited过的节点判断颜色即可。
cpp 复制代码
int n, m;
vector<list<int>>g(150009);
vector<int>visited(150009, 0);
vector<int>colors(150009, 0);
bool dfs(int x) {
	for (auto item : g[x]) {
		if (!visited[item]) {
			visited[item] = 1;
			colors[item] = !colors[x];
			if (!dfs(item)) {
				return false;
			}
		}
		else {
			if (colors[item] == colors[x]) {
				return false;
			}
		}
	}
	return true;
}
void solve() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for (int i = 1; i <= n; i++) {
		if (!visited[i]) {
			visited[i] = 1;
			colors[i] = 1;
			if (!dfs(i)) {
				cout << "No";
				return;
			}
		}
	}
	cout << "Yes";
}

匈牙利算法

二分图的匹配定义

给定一个二分图 G = ( U , V , E ) G = (U, V, E) G=(U,V,E),图 G G G 的一个匹配(matching) M M M 是边集 E E E 的一个子集,即 M ⊆ E M \subseteq E M⊆E,满足:M M M 中的任意两条边都没有公共顶点

例题

实现

  • 遍历每一个节点每一条边,尝试为每一个节点找一个匹配节点,如果当前匹配节点已经被之前的节点匹配了,就可以尝试为之前的节点再找一个新的匹配节点
  • 注意:visited数组不是全局的,当前节点和之前节点共用
cpp 复制代码
int n1, n2, m, ans;
vector<list<int>>g(509);
int visited[509];// 防止重边u-v
int fa[509];
bool find(int x) {
	for (auto item : g[x]) {
		if (!visited[item]) {
			visited[item] = 1;
			if (fa[item]) {
				if (find(fa[item])) {
					fa[item] = x;
					return true;
				}
			}
			else {
				fa[item] = x;
				return true;
			}
		}
	}
	return false;
}
void solve() {
	cin >> n1 >> n2 >> m;
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
	}
	for (int i = 1; i <= n1; i++) {
		memset(visited, 0, sizeof visited);
		if (find(i)) {
			ans++;
		}
	}
	cout << ans;
}
相关推荐
汀、人工智能5 小时前
[特殊字符] 第66课:跳跃游戏
数据结构·算法·数据库架构·图论·bfs·跳跃游戏
汀、人工智能5 小时前
[特殊字符] 第70课:加油站
数据结构·算法·数据库架构·图论·bfs·加油站
汀、人工智能5 小时前
[特殊字符] 第57课:搜索旋转排序数组
数据结构·算法·数据库架构·图论·bfs·搜索旋转排序数组
汀、人工智能9 小时前
[特殊字符] 第67课:跳跃游戏II
数据结构·算法·数据库架构·图论·bfs·跳跃游戏ii
苏纪云10 小时前
洛谷题目练习——二分+搜索+贪心+数学
算法·图论
君义_noip11 小时前
信息学奥赛一本通 4149:【GESP2509七级】连通图 | 洛谷 P14077 [GESP202509 七级] 连通图
c++·图论·gesp·信息学奥赛
汀、人工智能2 天前
[特殊字符] 第74课:完全平方数
数据结构·算法·数据库架构·图论·bfs·完全平方数
ambition202422 天前
斐波那契取模问题的深入分析:为什么提前取模是关键的
c语言·数据结构·c++·算法·图论
汀、人工智能2 天前
[特殊字符] 第73课:打家劫舍
数据结构·算法·数据库架构·图论·bfs·打家劫舍
汀、人工智能2 天前
[特殊字符] 第41课:翻转二叉树
数据结构·算法·数据库架构·图论·bfs·翻转二叉树