二分图的判断:leetcode 785(AC代码在下面)
二分图的定义:
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
二分图的判断(该图是否为二分图):
链接矩阵表示的图的判断:
-
[染色法 ] :选定图中的某一节点,将此节点染成黑色,将他的邻接点都染成红色;算法结束后,图中任意一节点(已经被染色)的颜色与它所有邻接点的颜色不相同(如:某一节点为黑色,那么它的所有邻接点都为红色),如果该条件不成立则该图不是二分图;
-
[ 实现方法] :广度优先遍历
-
1.选中一个有邻接点并且没有被染色的节点加入队列
-
2.检测队列是否为空,不为空,取出队列的头作为活结点
-
3.将它的所有的没有被染过色的邻接点加入队列中,并给这个邻接点染色
-
4.循环 2,3步; 队列为空就结束循环;
-
5.循环所有节点,满足”任意一节点(已经被染色)的颜色与它所有邻接点的颜色不相同“,就是二分图;
-
[细节] :题目给出的图,可能是由几个连通子图构成的; 只需给每一个连通子图都进行一次算法判断,如果其中有一个连通子图不是二分图那么整个图就不是二分图;
下面是伪代码:
while(true){
queue q[2];
a = 0, b = 1;
for(选中一个节点(有邻接点并且没有被染色)加入队列) q[a].push(节点);
if(q[a]为空) 所有连通子图都判断过了; break;
while(q[a]不为空){
染色笔 = !染色笔 //换种颜色
while(q[a]队列不为空){
top = q.pop() //弹出队列的头
for(循环top的所有邻接点){
if(没有被染色){
q[b].push(节点);
将它的所有的没有被染过色的邻接点加入队列中,并给这个邻接点染色
}
}
}
swap(a,b);
}
for()//循环所有节点,
if(不满足”任意一节点(已经被染色)的颜色与它所有邻接点的颜色不相同“)
return false;
}
return true;
下面是AC代码:
leetcode 785:
class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
if (graph.size() == 0) return 0;
vector<int> vist(graph.size(),-1);
queue<int> q[2];
bool f = 1;
int a = 0, b = 1;
while (true) {
for (int i = 0; i < graph.size(); i++) {
if (graph[i].size() != 0 && vist[i] == -1) {
q[a].push(i);
vist[i] = f;
break;
}
}
if (q[a].empty()) break;
while (!q[a].empty()) {
f = !f;
while (!q[a].empty()) {
int top = q[a].front();
q[a].pop();
//if (vist[top] != -1) continue;
for (int i = 0; i < graph[top].size(); i++) {
if (vist[graph[top][i]] == -1) {
q[b].push(graph[top][i]);
// cout << graph[top][i] << " ";
}
vist[graph[top][i]] = f;
}
//cout << endl;
}
swap(a, b);
}
for (int i = 0; i < graph.size(); i++) {
if (vist[i] == -1) continue;
for (int j = 0; j < graph[i].size(); j++) {
if ( vist[i] == vist[graph[i][j]])
return false;
}
}
}
return true;
}
};