二分图定义:
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。
题目
对于图中的任意两个节点 u 和 v,如果它们之间有一条边直接相连,那么 u 和 v 必须属于不同的集合。
如果给定的无向图连通,那么我们就可以任选一个节点开始,给它染成红色。随后我们对整个图进行遍历,将该节点直接相连的所有节点染成绿色,表示这些节点不能与起始节点属于同一个集合。我们再将这些绿色节点直接相连的所有节点染成红色,以此类推,直到无向图中的每个节点均被染色。
如果我们能够成功染色,那么红色和绿色的节点各属于一个集合,这个无向图就是一个二分图;如果我们未能成功染色,即在染色的过程中,某一时刻访问到了一个已经染色的节点,并且它的颜色与我们将要给它染上的颜色不相同,也就说明这个无向图不是一个二分图。
算法的流程如下:
可以使用「深度优先搜索」或「广度优先搜索」对无向图进行遍历,下文分别给出了这两种搜索对应的代码。
注意:题目中给定的无向图不一定保证连通,因此我们需要进行多次遍历,直到每一个节点都被染色,或确定答案为False 为止。每次遍历开始时,我们任选一个未被染色的节点,将所有与该节点直接或间接相连的节点进行染色。
class Solution {
private:
bool valid;
vector<int> color;
int UNCOLORED=0;
int RED=1;
int GREEN=2;
public:
bool isBipartite(vector<vector<int>>& graph) {
int n=graph.size();
valid=true;
color.assign(n,UNCOLORED);
for(int i=0;i<n&&valid;i++){
if(color[i]==UNCOLORED){
dfs(i,RED,graph);
}
}
return valid;
}
void dfs(int x,int COLOR,vector<vector<int>> &graph){
color[x]=COLOR;
int cNei=(COLOR==RED?GREEN:RED);
for(int nei:graph[x]){
if(color[nei]==UNCOLORED) {
dfs(nei,cNei,graph);
if(!valid){
return;
}
}else if(color[nei]!=cNei){
valid=false;
return;
}
}
}
};
class Solution {
private:
vector<int> color;
int UNCOLORED=0;
int RED=1;
int GREEN=2;
public:
bool isBipartite(vector<vector<int>>& graph) {
int n=graph.size();
color.assign(n,UNCOLORED);
for(int i=0;i<n;i++){
if(color[i]==UNCOLORED){
queue<int> qn;
qn.push(i);
color[i]=RED;
while(!qn.empty()){
int k=qn.front();qn.pop();
int cNei=(color[k]==RED?GREEN:RED);
for(int nei:graph[k]){
if(color[nei]==UNCOLORED){
qn.push(nei);
color[nei]=cNei;
}else if(color[nei]!=cNei){
return false;
}
}
}
}
}
return true;
}
};