【图论】——二分图
定义
*若一张
N
N
N节点无向图可以分为
A
,
B
A,B
A,B两个交集为空的非空集合,并且同一集合内部的点之间没有连通边,则称该图为二分图
定理
- 一张二分图中,一定没有不存在点数为奇数的环(否则环内会有点属于两边集合,矛盾)
二分图判定
染色法
- 使用黑白两种颜色,如果一个点当前为白色,则它所有邻边都是黑色
- 因此,当二分图中某一点颜色确定,图中所有点的颜色就都确定了
- 若发生冲突,则说明存在点数为奇数的环
- 可以用一个dfs来实现染色,复杂度为
O
(
n
+
m
)
O(n+m)
O(n+m)(点数加边数)
int n, m;
int e[N * 2], ne[N * 2], h[N], idx;
int color[N];
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
bool dfs(int x, int c)
{
color[x] = c;
for (int i = h[x]; i != -1; i = ne[i]) {
int j = e[i];
if (!color[j]) {
if (!dfs(j, 3 - c))
return false;
} else if (color[j] == c)
return false;
}
return true;
}
bool flag = true;
for (int i = 0; i < n; i++) {
if (!color[i]) {
if (!dfs(i, 1)) {
flag = false;
break;
}
}
}
二分图最大匹配——匈牙利算法(增广路算法)
最大匹配
- 任意两条边都没有公共端点,则称为一组匹配,包含边数最多的匹配称为最大匹配
- 若为二分图中的最大匹配,当且仅当该图中不存在该匹配的增广路
- 简而言之,不能有两个点公用一条边,都是
A
1
A_1
A1?对
B
1
B_1
B1?的关系,类似于“一夫一妻”
算法思路
- 遍历A或B其中一个集合
- 如果当前点的邻边未被占用,则用这条边将两点相连
- 如果邻边全部被占用,去寻找他的邻边是否有其他可以未被匹配的点,如果有,则更还邻边的匹配点,让他的邻边空出,让当前点与其相连
代码实现
int e[M], ne[M], h[N], idx;
bool st[N];
int match[N];
int n1, n2, m;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
bool dfs(int x)
{
for (int i = h[x]; i != -1; i = ne[i]) {
int j = e[i];
if (st[j])
continue;
st[j] = true;
if (!match[j] || dfs(match[j])) {
match[j] = x;
return true;
}
}
return false;
}
for (int i = 1; i <= n1; i++) {
memset(st, false, sizeof st);
if (dfs(i))
res++;
}
|