785. 判断二分图(C++)---DFS/ BFS 解题(包含介绍 自环边 和 平行边)

题目详情

给定一个无向图graph,当这个图为二分图时返回true。

如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。

graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。


示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释: 
无向图如下:
0----1
|       |
|       |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。

示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
解释: 
无向图如下:
0----1
|  \    |
|    \  |
3----2
我们不能将节点分割成两个独立的子集。

注意:

  • graph 的长度范围为 [1, 100]。
  • graph[i] 中的元素的范围为 [0, graph.length - 1]。
  • graph[i] 不会包含 i 或者有重复的值。
  • 图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。

 

——题目难度:中等



 


 

 

 前言

首先先介绍一下 自环边 平行边。
在图论中,存在两种相对比较特殊的边:
(1)自环边(self-loop):一个顶点到这个顶点自身的边  
(2)平行边(parallel-edges):两个顶点之间存在多条边相连接。
785. 判断二分图(C++)---DFS/ BFS 解题(包含介绍 自环边 和 平行边)_第1张图片

无论是自环边还是平行边,在很多时候也是有意义的。最典型的,如:对于交通运输来说,从 A 城市到 B 城市可能有不止一条路,可能有三条路,在这种情况下,平行边就非常有意义 但与此同时,自环边和平行边,会加大算法设计的难度,而且在很多情况下,我们真正关心的问题,其实是和自环边 或 平行边是无关的。最典型的,如:要考察一张图的连通性,那么自环边和平行边都不会改变这张图的连通性。

——资料来源:图论简介 - 阿特曼



 分析

根据二分图的定义,那么对于图中任意两个节点 u 和 v,如果它们之间有一条边直接相连,那么 u 和 v 就必须属于不同的集合。

遍历无向图可以使用「深度优先搜索」或「广度优先搜索」。

使用「深度优先搜索」:
算法流程如下:
1.选节点 0 开始,将其染成红色(1),并从该节点开始对整个无向图进行遍历
2.调用 dfs,如果我们通过节点 i 遍历到了节点 j(即 i 和 j 在图中有一条边直接相连),如果 i 和 j 的颜色相同,则直接返回 false;如果 j 还未被染色( j 还为 0 的话),就递归调用dfs 以此对 j 的直接相连的节点进行遍历,后面不断回溯遍历该图
3.遍历结束,如果中途没有返回 false 则说明给定的无向图是二分图,返回 true 作为答案。

-下面代码(DFS版)

class Solution {
public:
	bool dfs(vector>& graph, vector& cols, int i, int col) {
		cols[i] = col;
		for(int j : graph[i]) {
			if (cols[j] == cols[i]) return false;
			if (!cols[j] && !dfs(graph, cols, j, -col)) return false;
		}
		return true;
	}
	
    bool isBipartite(vector>& graph) {
    	int n = graph.size();
		vector cols(n, 0); 
		for(int i = 0; i < n; i++) {
			if (!cols[i] && !dfs(graph, cols, i, 1)) {
				return false;
			}
		}
		
		return true;
    }
};

785. 判断二分图(C++)---DFS/ BFS 解题(包含介绍 自环边 和 平行边)_第2张图片

 




使用「广度优先搜索」:
如果给定的无向图连通,那么我们就可以任选一个节点开始,给它染成红色(设为1)。随后我们对整个图进行遍历,将该节点直接相连的所有节点染成绿色(设为-1),表示这些节点不能与起始节点属于同一个集合, 并将没有染色的( j 为 0 )相连的所有节点入队。随后 依次出队,再将这些绿色(设为-1)节点 直接相连没有染色的( j 为 0 )节点染成红色(设为1),以此类推,直到无向图中的每个节点均被染色。
因为题目给定的无向图不一定保证连通,因此我们需要进行多次遍历,直到每一个节点都被染色,或确定答案为 False 为止。
遍历结束,如果中途没有返回 false 则说明给定的无向图是二分图,返回 true 作为答案。

 

 -下面代码(BFS版)

class Solution {
public:
    bool isBipartite(vector>& graph) {
    	int n = graph.size();
		vector cols(n, 0);
		queue q;
		
		for(int i = 0; i < n; i++) {
			
			if (!cols[i]) {
				q.push(i);
				cols[i] = 1;
				
				while (!q.empty()) {
					int node = q.front();
					q.pop();
					for(int j : graph[node]) {
						int temp = cols[node];
						if (temp == cols[j]) return false;
						if (!cols[j]) {
							cols[j] = -temp;
							q.push(j);
						}
					}
				}
				
			}
			
		}
		
		return true;
    }
};

785. 判断二分图(C++)---DFS/ BFS 解题(包含介绍 自环边 和 平行边)_第3张图片

你可能感兴趣的:(#,dfs,#,bfs,LeetCode-解题记录,dfs,bfs,图论,C++,leetcode)