二分图判定 :: labuladong的算法小抄 #1002
Replies: 30 comments 5 replies
-
js 785. 判断二分图 DFS 解法 var isBipartite = function(graph) {
const n = graph.length;
// 记录图是否符合二分图性质
let valid = true;
// 记录图中节点是否被访问(着色)过
const visited = {};
// 记录图中节点的颜色,false 和 true 代表两种不同颜色
const colors = new Array(n).fill(false);
// 因为图不一定是联通的,可能存在多个子图
// 所以要把每个节点都作为起点进行一次遍历
// 如果发现任何一个子图不是二分图,整幅图都不算二分图
for (let v = 0; v < n; v++) {
if (visited[v]) continue;
traverse(v);
}
return valid;
// DFS 遍历框架
function traverse(v) {
// 如果已经确定不是二分图了,就不用浪费时间再递归遍历了
if (!valid) return;
visited[v] = true;
for (const n of graph[v]) {
// 相邻节点被访问过
// 比较两个节点的颜色是否相同
// 比如相同,则不是二分图
if (visited[n]) {
if (colors[n] === colors[v]) {
valid = false;
return;
}
continue;
}
// 相邻节点没有被访问过
// 那么涂色
colors[n] = !colors[v];
// 继续遍历
traverse(n);
}
}
}; js 785. 判断二分图 BFS 解法 var isBipartite = function(graph) {
const n = graph.length;
// 记录图是否符合二分图性质
let valid = true;
// 记录图中节点是否被访问(着色)过
const visited = {};
// 记录图中节点的颜色,false 和 true 代表两种不同颜色
const colors = new Array(n).fill(false);
// 因为图不一定是联通的,可能存在多个子图
// 所以要把每个节点都作为起点进行一次遍历
// 如果发现任何一个子图不是二分图,整幅图都不算二分图
for (let v = 0; v < n; v++) {
if (visited[v]) continue;
traverse(v);
}
return valid;
// BFS 遍历框架
function traverse(start) {
const q = [start];
visited[start] = true;
while (q.length && valid) {
const v = q.shift();
// 从节点 v 向所有相邻节点扩散
for (const n of graph[v]) {
// 相邻节点被访问过
// 比较两个节点的颜色是否相同
// 比如相同,则不是二分图
if (visited[n]) {
if (colors[n] === colors[v]) {
valid = false;
return;
}
continue;
}
// 相邻节点没有被访问过
// 那么涂色
colors[n] = !colors[v];
visited[n] = true;
q.push(n);
}
}
}
}; js 886. 可能的二分法 let valid = true;
const colors = new Array(n + 1).fill(false);
const visited = [];
// 转化成邻接表表示图结构
const graph = buildGraph();
// 图节点编号从 1 开始
for (let v = 1; v <= n; v++) {
if (visited[v]) continue;
traverse(v);
}
return valid;
// 建图
function buildGraph() {
// 图节点编号为 1...n
const graph = new Array(n + 1).fill(0).map(
() => []
);
for (const [v, n] of dislikes) {
// 「无向图」相当于「双向图」
graph[v].push(n);
graph[n].push(v);
}
return graph;
}
function traverse(v) {
if (!valid) return;
visited[v] = true;
for (const n of graph[v]) {
if (visited[n]) {
// 相邻着色相同,说明不喜欢的两个人分到同一组了
if (colors[n] === colors[v]) {
valid = false;
return;
}
continue;
}
colors[n] = !colors[v];
traverse(n);
}
} |
Beta Was this translation helpful? Give feedback.
-
210「 课程表 II」的BFS解法则使用入度作为算法入口
当解答 785「 判断二分图」的时候,发现入度全部不为0,根本无法进入BFS循环。
那么我可不可以这么理解: |
Beta Was this translation helpful? Give feedback.
-
@omgwtfholyshit 你可以理解为, |
Beta Was this translation helpful? Give feedback.
-
明白了,如果不能通过下标找到下一个节点就得建图,或者说让每个数组下标代表一个人,下标所在元素(一个链表)代表这个人能走向的目的地.所以有时候根据二维数组的定义就是天然的邻接表,有些题得自己建 |
Beta Was this translation helpful? Give feedback.
-
785的dfs和bfs框架,为什么bfs里if not visited[w]以后需要标记该节点为已访问而dfs不需要呢,一直没有想清楚。。 |
Beta Was this translation helpful? Give feedback.
-
@Yuguo-Wang DFS 是在递归的前序遍历位置标记该节点,和 BFS 入队前标记该节点本质上是一样的 |
Beta Was this translation helpful? Give feedback.
-
C++ #include <vector>
using namespace std;
class Solution{
public:
vector<bool> color; // 给结点染色
vector<bool> visited; // 保存访问过的结点
bool isBi = true; // 是否符合二分图
bool isBipartite(vector<vector<int>> &graph){
visited.resize(graph.size());
color.resize(graph.size());
for (int i = 0; i < graph.size(); i++)// 图可能并不连通
if (!visited[i] && isBi) traverse(graph, i);
return isBi;
}
void traverse(vector<vector<int>> &graph, int v){
visited[v] = true;
for (int n : graph[v]) {// 遍历顶点v的所有邻居顶点
if (visited[n] == false) {
color[n] = !color[v];// 没访问过的顶点,染成反色
traverse(graph, n);
}
else{
if (color[n] == color[v]) isBi = false;// 两个相邻顶点同色,不符合二分图
}
}
}
}; 有帮助的话请点个赞再走~ |
Beta Was this translation helpful? Give feedback.
-
c++ bfs class Solution {
public:
bool ok {true};
vector<bool> visited;
vector<bool> color;
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
visited.resize(n);
color.resize(n);
for(int i = 0; i < n; i++) {
if(!visited[i]&&ok){
bfs(graph,i);
}
}
return ok;
}
void bfs(vector<vector<int>>& graph,int &s){
queue<int> q;
q.emplace(s);
while(!q.empty() && ok){
int v = q.front();
q.pop();
visited[v] = true;
for(const auto &w : graph[v]){
if(!visited[w]){
color[w] = !color[v];
q.emplace(w);
}else if(color[w] == color[v]){
ok = false;
return;
}
}
}
}
}; |
Beta Was this translation helpful? Give feedback.
-
785 Python3 class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
#DFS
self.isBp = True
self.visited = set()
self.colormap = {}
for i in range(len(graph)):
#已遍历过的连接子图跳过
if i not in self.visited:
self.colormap[i] = 0
self.traverse(i,graph)
return self.isBp
def traverse(self,node,graph):
if not self.isBp:
return
self.visited.add(node)
for nextnode in graph[node]:
if nextnode not in self.visited:
self.colormap[nextnode] = (self.colormap[node] + 1) % 2
self.traverse(nextnode,graph)
else:
if self.colormap[nextnode] == self.colormap[node]:
self.isBp = False
return
return BFS class Solution:
#BFS
def isBipartite(self, graph: List[List[int]]) -> bool:
isBp = True
colormap = {}
visited = set()
for i in range(len(graph)):
#已遍历过的连接子图跳过
if i not in visited:
queue = deque()
queue.append(i)
visited.add(i)
colormap[i] = 0
while queue and isBp:
curNode = queue.popleft()
for nextNode in graph[curNode]:
if nextNode not in visited:
colormap[nextNode] = (colormap[curNode] + 1) % 2
queue.append(nextNode)
visited.add(nextNode)
else:
if colormap[nextNode] == colormap[curNode]:
isBp = False
break
return isBp |
Beta Was this translation helpful? Give feedback.
-
滴滴滴打卡 |
Beta Was this translation helpful? Give feedback.
-
多谢东哥的分享很有用 |
Beta Was this translation helpful? Give feedback.
-
滴滴打卡 |
Beta Was this translation helpful? Give feedback.
-
学到了! |
Beta Was this translation helpful? Give feedback.
-
lt 886 bfs class Solution {
boolean ok = true;
boolean[] visited;
boolean[] color;
public boolean possibleBipartition(int n, int[][] dislikes) {
visited = new boolean[n+1];
color = new boolean[n+1];
List<Integer>[] graph = buildGraph(n, dislikes);
for (int i = 1; i < n+1; i++) {
if(!visited[i]) traverse(graph, i);
}
return ok;
}
List<Integer>[] buildGraph(int n, int[][] graph) {
List<Integer>[] res = new LinkedList[n+1];
for(int i = 1; i <= n; i++) {
res[i] = new LinkedList<>();
}
for (int[] edge: graph) {
int v = edge[0];
int w = edge[1];
res[v].add(w);
res[w].add(v);
}
return res;
}
void traverse(List<Integer>[] graph, int v) {
if(!ok) return;
visited[v] = true;
Queue<Integer> q = new LinkedList<>();
q.offer(v);
while(!q.isEmpty()) {
int t = q.poll();
for(int w : graph[t]) {
if(!visited[w]) {
color[w] = !color[t];
visited[w] = true;
q.add(w);
} else {
if(color[w] == color[t]) {
ok = false;
return;
}
}
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
C++ 实现检测二分图 class Solution {
public:
bool ok = true;
vector<bool> colors;
vector<bool> visited;
queue<int> q;
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
colors = vector<bool>(n, false);
visited = vector<bool>(n, false);
for (int i = 0; i < n; i ++) {
if (!visited[i])
// dfs(i, graph);
bfs(i, graph);
}
return ok;
}
void bfs(int node, vector<vector<int>>& graph) {
visited[node] = true;
q.push(node);
while (q.size() && ok) {
int v = q.front(); q.pop();
for (int w : graph[v]) {
if (!visited[w]) {
colors[w] = !colors[v];
visited[w] = true;
q.push(w);
} else {
if (colors[w] == colors[v]) {
ok = false;
return;
}
}
}
}
}
void dfs(int v, vector<vector<int>>& graph) {
if (!ok) return;
visited[v] = true;
for (int w: graph[v]) {
if (!visited[w]) {
colors[w] = !colors[v];
dfs(w, graph);
} else {
if (colors[w] == colors[v]) ok = false;
}
}
}
}; |
Beta Was this translation helpful? Give feedback.
-
C++ 886题的实现
|
Beta Was this translation helpful? Give feedback.
-
为什么这里不需要onPath呢 |
Beta Was this translation helpful? Give feedback.
-
请问东哥,886题,为什么在构建无向图时,写成“graph[w].add(v); graph[v].add(w);“时无法通过n=2000时的用例?谢谢 |
Beta Was this translation helpful? Give feedback.
-
C++ class Solution {
public:
bool ok = true;
vector<bool> color;
vector<bool> visited;
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
color.resize(n, false);
visited.resize(n, false);
for (int v = 0; v < n; v ++) {
if(!visited[v]) {
bfs(graph, v);
}
}
return ok;
}
void bfs(vector<vector<int>> &graph, int v) {
if (!ok) {
return;
}
queue<int> q;
q.push(v);
while (q.size() && ok) {
int start = q.front();
q.pop();
visited[start] = true;
for (auto node: graph[start]) {
if(!visited[node]) {
q.push(node);
color[node] = !color[start];
} else {
if (color[node] == color[start]) {
ok = false;
return;
}
}
}
}
}
}; |
Beta Was this translation helpful? Give feedback.
-
有一点想不通,为什么886这题一定要构建无向图才能通过,构造有向图会挂。我想不通这个corner case,我觉得有向图也可以解决这个问题呀 |
Beta Was this translation helpful? Give feedback.
-
看到了一道应该是判断二分图的变种,不知道该怎么做了,不是相邻颜色必须不同,而是只要不是红色就行 给一个无向图染色,可以填红黑两种颜色,必须保证相邻两个节点不能同时为红色,输出有多少种不同的染色方案? 示例1: |
Beta Was this translation helpful? Give feedback.
-
这个和上一个拓朴排序的回溯可以一样么,就是在遍历图的时候 |
Beta Was this translation helpful? Give feedback.
-
感觉还是尽量少写这种将答案作为全局变量的代码,破坏了方法的封装性。 |
Beta Was this translation helpful? Give feedback.
-
不是很理解用dislikes建图,dislikes和graph不是同一个东西吗? |
Beta Was this translation helpful? Give feedback.
-
我有点不太明白,那个染色的二分图,左边的那个两个蓝的连起来不就不是二分图了?右边的那个两个蓝的不连,不就是二分图了?是不是 不是只是染色的结果。因为还得看定义的边? |
Beta Was this translation helpful? Give feedback.
-
您好,已收到。
|
Beta Was this translation helpful? Give feedback.
-
东哥,为什么判断二分图需要使用无向图啊,使用有向图不可以吗 |
Beta Was this translation helpful? Give feedback.
-
您好,已收到。
|
Beta Was this translation helpful? Give feedback.
-
大佬🐂皮 |
Beta Was this translation helpful? Give feedback.
-
您好,已收到。
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:二分图判定
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions