二分图判定算法
二分图判定算法
- 判断二分图
- dfs遍历
- bfs遍历
- 可能的二分法
- bfs遍历
- dfs遍历
二分图判定说白了就是遍历一遍图,一边遍历一边染色,看看能不能用两种颜色给所有节点染色,且相邻节点的颜色都不相同。
// 图遍历框架dfs
var traverse = function(graph, visited, v) {
visited[v] = true;
// 遍历节点 v 的所有相邻节点 neighbor
for (var neighbor of graph.neighbors(v)) {
if (!visited[neighbor]) {
// 相邻节点 neighbor 没有被访问过
// 那么应该给节点 neighbor 涂上和节点 v 不同的颜色
traverse(graph, visited, neighbor);
} else {
// 相邻节点 neighbor 已经被访问过
// 那么应该比较节点 neighbor 和节点 v 的颜色
// 若相同,则此图不是二分图
}
}
}
判断二分图
链接
dfs遍历
class Solution {
//用dfs遍历一遍图
boolean res=true;
boolean []visit;//保证每个节点只当一次start向四周染色
boolean []col;
public boolean isBipartite(int[][] graph) {
int sz=graph.length;//节点的个数
visit=new boolean[sz];
col=new boolean[sz];
for(int i=0;i<sz;i++){
if(!visit[i]){
dfs(graph,i);
}
}
return res;
}
void dfs(int[][]graph,int start){
if(res==false){
return;
}
visit[start]=true;
for(int neibor:graph[start]){
if(!visit[neibor]){
//染色
col[neibor]=!col[start];
dfs(graph,neibor);
}else{
//判断
if(col[neibor]==col[start]){
res=false;
return;
}
}
}
}
}
bfs遍历
class Solution {
public boolean isBipartite(int[][] graph) {
int n=graph.length;
boolean[]visit=new boolean[n];//记录进队列的节点,保证每个节点只进一次,进一次就相当于以这个节点为start了向四周染色了
boolean[]col=new boolean[n];
Queue<Integer> q=new LinkedList();
for(int i=0;i<n;i++){
if(visit[i]){
continue;
}
//从i开始bfs
q.add(i);
visit[i]=true;
while(!q.isEmpty()){
int cur=q.poll();
for(int neibor:graph[cur]){
if(!visit[neibor]){
//染色
col[neibor]=!col[cur];
q.add(neibor);
visit[neibor]=true;
}else{
//检查
if(col[neibor]==col[cur]){
return false;
}
}
}
}
}
return true;
}
}
可能的二分法
链接
bfs遍历
class Solution {
//染过颜色就visit标记一下,然后进队列,进了队列就一定会出队列,出队列就会以它为中心向四周染色,visit[i]为真代表以i为中心向四周染色过
public boolean possibleBipartition(int n, int[][] dislikes) {
//先创建图,然后将图染色
List<Integer>[]graph=new LinkedList[n+1];
for(int i =1;i<=n;i++){
graph[i]=new LinkedList();
}
for(int []e:dislikes){
int a=e[0];
int b=e[1];
graph[a].add(b);
graph[b].add(a);
}
boolean[]visit=new boolean[n+1];
Queue<Integer> q=new LinkedList();
boolean[]col=new boolean[n+1];
for(int i=1;i<=n;i++){
if(visit[i]){
continue;
}
q.add(i);
visit[i]=true;
while(!q.isEmpty()){
int cur=q.poll();
for(int neibor:graph[cur]){
if(!visit[neibor]){
//染色
col[neibor]=!col[cur];
q.add(neibor);
visit[neibor]=true;
}else{
//判断
if(col[neibor]==col[cur]){
return false;
}
}
}
}
}
return true;
}
}
dfs遍历
class Solution {
boolean[]col;
boolean[]visit;//保证了每个节点都当过start一次,向四周染色
boolean isBi=true;
public boolean possibleBipartition(int n, int[][] dislikes) {
//先创建图,然后将图染色
List<Integer>[]graph=new LinkedList[n+1];
for(int i =1;i<=n;i++){
graph[i]=new LinkedList();
}
for(int []e:dislikes){
int a=e[0];
int b=e[1];
graph[a].add(b);
graph[b].add(a);
}
visit=new boolean[n+1];//visit[i]=true说明 以i为start向四周染色过
col=new boolean[n+1];
for(int i=1;i<=n;i++){
if(!visit[i]){//没有以i为start过
dfs(graph,i);
}
if(isBi==false){
return false;
}
}
return true;
}
//定义:从start开始遍历图,一边遍历一边涂色
void dfs(List<Integer>[]graph,int start){
if(!isBi){
//已经知道不是二分图
return;
}
visit[start]=true;
for(int neibor:graph[start]){
if(!visit[neibor]){
//涂色
col[neibor]=!col[start];
dfs(graph,neibor);
}else{
if(col[neibor]==col[start]){
isBi=false;
return;
}
}
}
}
}