定义
对于二分图,就个人理解,是一种可以将顶点划分成两个集合的无向图,和顶点连接的边每一条都连接着这两个集合,也就是说判定一个二分图就看这张图的任意边连接的两个顶点能不能归属于两个集合。有一个等价定义是:不含有「含奇数条边的环」的图。
以下举一个非二分图的例子:(显然这张图含有奇数条边的环)
无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
概念
- 什么是匹配?
匹配是一个集合的概念,这个集合包含多条边,并且这多条边没有公共的顶点。也就是说一个匹配集中有 n n n条边就对应着 2 ∗ n 2*n 2∗n个不同的顶点。(但是显然匹配并不一定包含着全部可匹配的点,所有匹配的极大集也就是最大匹配)。 - 什么是最大匹配?
一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。 - 什么是完美匹配?
一个图的某个匹配中,恰好包含所有顶点,也就是说所有点都是匹配点则称这是完美匹配。就是每个点都能够有唯一映射。 - 交替路是什么?
顾名思义,一种依次交替经过非匹配边、匹配边的路径。 - 增广路是什么?
顾名思义,增广,扩充的含义,实际上是扩充匹配集,即新加进来一个匹配边,两个匹配点。从未匹配点走交替路,来到另一个未匹配点,则称增广路。
判定
染色法,可以用深搜或者广搜来解决。核心思路是找一个点,染A色后对其邻点都染B色,如果某个邻点已经染色并且和它一样,则不是二分图,否则和它不一样就不用考虑它。
Code:
int color[maxnn]; //每个点的颜色
int n; //n个点
int head[maxnn], son[maxnm], nxt[maxnm], cnt; //链式前向星
//把当前的点cur染成颜色c
bool dfs(int cur, int c) {
color[cur] = c;
for (int i = head[cur]; ~i; i=nxt[i]) {
int v = son[i];
if (color[v] == c) return false; //发现邻居有已被染色并且和它一样显然不是二分图
if (!color[v] && !dfs(v, -c)) return false; //没被染色,染后发现这条搜索路径会不符合二分图
}
return true; //所有顶点都符合二分图的判定
}
bool solve() {
for (int i = 1; i <= n; i++)
if (!color[i] && !dfs(i, 1)) return false; //i点还没染色进去i所在的环判定
return true;
}