二分图
二分图,图论中的一种特殊模型。设
G=(V,E)
G
=
(
V
,
E
)
是一个无向图,如果顶点
V
V
可以分割成两个互不相交的子集,并且图中的每条边
(i,j)
(
i
,
j
)
所关联的两个顶点分别属于这两个不同的顶点集
(i in U,j in V)
(
i
i
n
U
,
j
i
n
V
)
,则称图G为一个二分图。
二分图的判定条件:
1.G至少有两个顶点。
2.所有回路的长度均为偶数。
可以将 U 和 V 当做 着色图: U 中所有节点为蓝色, V 中所有节点着绿色,每条边的两个端点的颜色不同,符合图着色问题的要求。相反,用这样的着色方式对非二分图是行不通的,根据triangle:其中一个顶点着蓝色并且另一个着绿色后,三角形的第三个顶点与上述具有两个颜色的顶点相连,无法再对其着蓝色或绿色。
二分图判断
交叉染色。
给一个无向图。要给图上每个顶点染色,并且使任意相邻的顶点染色不同。并且最多用两种颜色。如果可以进行二分图染色,证明是一个二分图。
题目
hdu4751,一堆人,每个人单方面认识一些人,希望把这些人分成两堆,使得每一堆的人都相互认识。
思路
若能分出两堆,A不认识B,B不认识C,则必然有A认识C。
所以根据不认识关系建立图,判断是否为二分图即可。
代码(二分图判断模板)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 100 + 10;
int n, knows[maxn][maxn], G[maxn][maxn], color[maxn];
bool dfs(int u, int c) {
color[u] = c;
_rep(v,1,n)
if (G[u][v] && v != u) {
if (color[v] == c) return false;
if (color[v] == 0 && !dfs(v, -c)) return false;
}
return true;
}
bool solve() {
_rep(i, 1, n)
if (color[i] == 0 && !dfs(i, 1))
return false;
return true;
}
int main() {
while (scanf("%d", &n) == 1 && n) {
int v;
memset(knows, 0, sizeof(knows));
_rep(u, 1, n) {
while (1) {
scanf("%d", &v);
if (v == 0) break;
knows[u][v] = 1;
}
}
memset(G, 0, sizeof(G));
_rep(u,1,n)
_rep(v,1,n)
if (!knows[u][v] || !knows[v][u])
G[u][v] = G[v][u] = 1;
memset(color, 0, sizeof(color));
if (solve()) printf("YES\n");
else printf("NO\n");
}
return 0;
}
本题实际是在为团队分组那道题做铺垫。