二分图
1. 二分图的判断
一个图是二分图<=>当且仅当图中不含奇数环。
如何判断一个图是否是二分图?等价于用2种颜色的染色法染图,如果没有冲突,说明是二分图;冲突的话不是二分图。
步骤:
step1:依次遍历 n
个节点
step2: 如果当前点没有染色,则把当前点所在的连通块用dfs的方法全部染色;dfs染色的返回值表示当前点染色过程中是否有冲突?如果有冲突,则不是二分图;如果没有冲突,则是二分图。
代码模板
时间复杂度O(n + m)
bool dfs(int p, int c)
{
color[p] = c;
for(int i = h[p]; i != -1; i = ne[i])
{
int j = e[i];
if(color[j] == 0) {
if(dfs(j, 3 - c) == false) return false;
} else if(color[j] == c) return false;
}
return true;
}
bool bi_part_graph()
{
for(int i = 1; i <= n; i++)
{
if(color[i] == false)
{
if(dfs(i, 1) == false) return false;
}
}
return true;
}
2.二分图的最大匹配
Step1: 对二分图的每个节点 h[i]
,试图为当前节点 j
找一个配对节点
Step2: 具体寻找过程,依次遍历当前节点 j
的所有邻接点 t
,如果 t
没有配对或者可以为 t
配对的对端节点重新配对,则当前节点 j
可以和 t
配对;如果 j
不能和所有邻接点配对,则 t
无法配对
代码模板
时间复杂度最坏情况下O(nm), 实际情况下远小于O(nm)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510, M = 100010;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];
int st[N];
void init()
{
memset(h, -1, sizeof h);
idx = 0;
}
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
int find(int x)
{
for(int i = h[x]; i != -1; i = ne[i])
{
int j = e[i];
if(st[j] == false)
{
st[j] = true;
if(match[j] == false || find(match[j]) == true)
{
match[j] = x;
return true;
}
}
}
return false;
}
int main()
{
cin >> n1 >> n2 >> m;
init();
while(m--)
{
int a, b;
cin >> a >> b;
add(a, b);
}
int res = 0;
for(int i = 1; i <= n1; i++)
{
memset(st, 0, sizeof st);
if(find(i)) res ++;
}
cout << res << endl;
return 0;
}