搜索&图论_785.判断二分图(20200716)

文章目录

    • 分析
    • 算法流程:
    • DFS
    • BFS

分析

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

  2. 如果给定的无向图连通,那么我们任选一个节点开始,染成红色。随后我们对整个图进行遍历,将该节点直接相连的所有节点染成绿色,表示这些节点不能与起始节点属于同一个集合。我们再将这些绿色节点直接相连的所有节点染成红色,以此类推,直到无向图中的每个节点均被染色。

  3. 如果我们能够成功染色,那么红色和绿色的节点各属于一个集合,这个无向图就是一个二分图;如果我们未能成功染色,即在染色的过程中,某一时刻访问到了一个已经染色的节点,并且它的颜色与我们将要给它染上的颜色不相同,也就说明这个无向图不是一个二分图。

算法流程:

(染色法)
我们任选一个节点开始,将其染成红色,并从该节点开始对整个无向图进行遍历;

  1. 在遍历的过程中,如果我们通过节点 u 遍历到了节点 v(即 u 和 v 在图中有一条边直接相连),那么会有两种情况:

    1.1 如果 v 未被染色,那么我们将其染成与 uu 不同的颜色,并对 v 直接相连的节点进行遍历;

    1.2 如果 v 被染色,并且颜色与 u 相同,那么说明给定的无向图不是二分图。我们可以直接退出遍历并返回 False 作为答案。

  2. 当遍历结束时,说明给定的无向图是二分图,返回 True 作为答案。

注意:题中给定的无向图不一定保证连通,需要进行多次遍历,直到每一个节点都被染色,或确定答案为 False 为止。每次遍历开始时,我们任选一个未被染色的节点,将所有与该节点直接或间接相连的节点进行染色。

DFS

class Solution {
private:
    static constexpr int UNCOLORED = 0;
    static constexpr int RED = 1;
    static constexpr int GREEN = 2;
    vector<int> color;
    bool valid;

public:
    void dfs(int node, int c, const vector<vector<int>>& graph) {
        color[node] = c;
        int cNei = (c == RED ? GREEN : RED);
        for (int neighbor: graph[node]) {
            if (color[neighbor] == UNCOLORED) {
                dfs(neighbor, cNei, graph);
                if (!valid) {
                    return;
                }
            }
            else if (color[neighbor] != cNei) {
                valid = false;
                return;
            }
        }
    }

    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;
    }
};

// 2.
class Solution {
public:
    // 返回值表示从当前节点开始dfs,是否可以二分
    bool dfs(vector<vector<int>>& graph, int now, int c, vector<int>& color) {
        color[now] = c; // 着色
        c = -c; // 邻居着相反色
        for (auto& adj : graph[now]) {
            if (color[adj] == 0) {
                // 邻居还没有访问过
                if (!dfs(graph, adj, c, color))
                    return false;
            } // 邻居访问过且和当前颜色相同 
            else if (color[adj] == color[now])
                return false;
        }
        return true;
    }
    // 着色法
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> color(n, 0);
        // 对每个没有访问过的起点dfs
        for (int i = 0; i < n; ++i) {
            if (color[i] == 0 && !dfs(graph, i, 1, color))
                return false;
        }
        return true;
    }
};

BFS

class Solution {
private:
    static constexpr int UNCOLORED = 0;
    static constexpr int RED = 1;
    static constexpr int GREEN = 2;
    vector<int> color;

public:
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> color(n, UNCOLORED);
        for (int i = 0; i < n; ++i) { // 枚举每个点
         	// 如果当前点未着色 进行判断,否则直接跳过
            if (color[i] == UNCOLORED) {
                queue<int> q;
                q.push(i);
                color[i] = RED;
                // bfs 遍历每个邻接点
                while (!q.empty()) {
                    int node = q.front();
                    int cNei = (color[node] == RED ? GREEN : RED);
                    q.pop();
                    for (int neighbor: graph[node]) {
                        if (color[neighbor] == UNCOLORED) {
                            q.push(neighbor);
                            color[neighbor] = cNei;
                        }
                        else if (color[neighbor] != cNei) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
};

你可能感兴趣的:(Miracle,wandering,in,LeetCode)