图论·二分图

文章目录

二分图的定义

形式化定义

一个二分图 (又称二部图 ,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;
}
相关推荐
Mortalbreeze5 天前
0 - 1 BFS 算法详解:从基本原理到经典题目建模
数据结构·c++·算法·图论·宽度优先
一去不复返的通信er5 天前
力扣-图论-岛屿数量
算法·leetcode·图论
春弦_8 天前
自用算法整理二
数据结构·算法·图论
lvwangshu9 天前
P8981 「DROI」Round 1 距离 题解
动态规划·图论·题解·dp·树形dp·技巧·换根dp·性质题·思维好题
海海不掉头发10 天前
图论与应用_课堂笔记
笔记·图论
云淡风轻~窗明几净10 天前
角谷猜想最接近严格证明的测试 Version1.1.1
人工智能·算法·机器学习·图论
云淡风轻~窗明几净10 天前
角谷猜想与百度AI的对话dialog(原始稿)
人工智能·算法·机器学习·图论
罗湖老棍子11 天前
【例 1】Sightseeing Trip(信息学奥赛一本通- P1494)(洛谷-P10927)
数据结构·算法·图论·最短路·floyd·最小环
罗湖老棍子12 天前
【例题1】黑暗城堡(信息学奥赛一本通- P1486)
算法·图论·最短路·dijkstra·最小生成树·最短路径生成树
Coder-magician13 天前
图论总结篇
算法·图论