二分图
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
从上面的例子我们可以看到,二分图中的顶点可以分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。
我们可以对两个点集进行 **“染色”**从而进行区分,这也给了我们判断一个图是否为二分图的思路:
- 遍历图中所有顶点,交替染色,如果在染色的过程中,发现一个顶点v的邻点w颜色与该顶点v相同,那么显然该图不是一个二分图。如果所有顶点都被成功的交替染色,那么最终可以判断原图G是二分图。
染色法代码
算法的代码如下(C++版本):
#define Max 10001
#define white 0 //white表示该顶点还未被遍历到,没有颜色
#define blue 1 //以red和blue作为染色的颜色
#define red 2
#include<iostream>
using namespace std;
int n, m;
int adj[Max][Max]; //邻接表
int color[Max]; //存储顶点颜色的数组
void Init() //初始化邻接矩阵和颜色数组
{
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
adj[i][j] = 0;
for (int i = 0; i < n; i++)
color[i] = white;
}
bool dyeing_judge(int s,int s_color) //染色法,用DFS对图进行遍历
{
color[s] = s_color; //将顶点s先染成指定颜色
for (int i = 0; i < n; i++)
{
if (adj[s][i] != 0) { //对于s相邻的每个顶点v
if (color[i] == s_color) //如果v已经在之前的遍历染成相同的颜色
return false; //说明原图不是二部图,返回false
else if (color[i] == white) { //如果v没有被染色
int c = color[s] == blue ? red : blue; //交替指定颜色
return dyeing_judge(i, c); //DFS遍历v
}
}
}
return true; //所有顶点染色成功,返回true
}
int main()
{
cin >> n >> m; //输入顶点、边的数量
int s, t;
Init(); //初始化
for (int i = 0; i < m; i++) {//依次输入边
cin >> s >> t;
adj[s-1][t-1] = 1;
adj[t-1][s-1] = 1;
}
bool judge = dyeing_judge(0, red);
//输出判断:是否是二分图
if (judge)cout << "yes" << endl;
else cout << "no" << endl;
}
测试样例
输入:
3 3
1 2
2 3
1 3
输出:
no
输入:
2 1
1 2
输出:
yes
时间复杂度分析
初始化的复杂度为
O
(
n
)
O(n)
O(n),染色DFS遍历的时间复杂度为
O
(
m
+
n
)
O(m+n)
O(m+n)。
算法的总时间复杂度为
O
(
m
+
n
)
O(m+n)
O(m+n)。