886. Possible Bipartition


Given a set of N people (numbered 1, 2, …, N), we would like to split everyone into two groups of any size.

Each person may dislike some other people, and they should not go into the same group.

Formally, if dislikes[i] = [a, b], it means it is not allowed to put the people numbered a and b into the same group.

Return true if and only if it is possible to split everyone into two groups in this way.

Example 1:

Input: N = 4, dislikes = [[1,2],[1,3],[2,4]]
Output: true
Explanation: group1 [1,4], group2 [2,3]

Example 2:

Input: N = 3, dislikes = [[1,2],[1,3],[2,3]]
Output: false

Example 3:

Input: N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
Output: false

Note:

  1. 1 <= N <= 2000
  2. 0 <= dislikes.length <= 10000
  3. 1 <= dislikes[i][j] <= N
  4. dislikes[i][0] < dislikes[i][1]
  5. There does not exist i != j for which dislikes[i] == dislikes[j].

方法1: dfs

花花:https://zxi.mytechroad.com/blog/graph/leetcode-886-possible-bipartition/

思路:

这个bipartite的朴素版,太慢了。主要是adjacency matrix占用了过大的空间。

class Solution {
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
        vector<vector<int>> graph(N + 1, vector<int>(N + 1));
        for (auto dis: dislikes) {
            graph[dis[0]][dis[1]] = 1;
            graph[dis[1]][dis[0]] = 1;
        }
        
        vector<int> colors(N + 1, 0);
        for (int i = 1; i < N + 1; i ++) {
            if (!colors[i] && !bipartiteHelper(graph, colors, i, 1)) {
                return false;
            }
        }
        return true;
    }
    
    
    bool bipartiteHelper(vector<vector<int>> & graph, vector<int> & colors, int i, int color){
        
        colors[i] = color;
        
        for (int j = 1; j < graph.size(); j++) {
            if (graph[i][j]) {
                if (colors[j] && colors[j] == color) return false;
                if (!colors[j] && !bipartiteHelper(graph, colors, j, -color)) 
                    return false;
            }
        }
        return true;
    }
};

改进成Adjacency list, 一开始并不开(N+1) * (N + 1) 的矩阵,只将所有边push_back

class Solution {
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
        vector<vector<int>> graph(N + 1);
        for (auto dis: dislikes) {
            graph[dis[0]].push_back(dis[1]);
            graph[dis[1]].push_back(dis[0]);
        }
        vector<int> colors(N + 1, 0);
        for (int i = 1; i < N + 1; i++) {
            if (!colors[i] && !bipartiteHelper(graph, colors, i, 1)) return false;
        }
        return true;
    }
    
    bool bipartiteHelper(vector<vector<int>> & graph, vector<int> & colors, int i, int color) {
        colors[i] = color;
        for (int j : graph[i]) {
            if (colors[j] == color) return false;
            if (!colors[j] && !bipartiteHelper(graph, colors, j, -color)) return false;
        }
        return true;
    }
};

方法2: bfs

思路:

方法3: Union find

grandyang: https://www.cnblogs.com/grandyang/p/10317141.html

思路:

用union find的思想来看,这道题的目的就是将所有人没有冲突的union 成两个阵营。把谁和谁进行union呢?对于i来讲,1. 他的所有敌人需要被union在一起,也就是auto j:graph[i],2. i要和每一个j的每个敌人k,union起来。这里用循环拆分,每个循环中只需要进行两次必要的检查:

  1. i 和 所有graph[i][j] 不能够是一个颜色,如果一样false
  2. 确认第一点后,assume parent1 = uf(i), parent2 = uf(j[0]),那么要将所有jk都union成parent2的颜色。
class Solution {
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
        vector<vector<int>> graph(N + 1);
        for (auto dis: dislikes) {
            graph[dis[0]].push_back(dis[1]);
            graph[dis[1]].push_back(dis[0]);
        }
        vector<int> root(N + 1, -1);
        for (int i = 1; i < N + 1; i ++ ) root[i] = i;
        
        for (int i = 1; i < N + 1; i++ ) {
            if (graph[i].empty()) continue;
            int parent1 = unionHelper(root, i);
            int parent2 = unionHelper(root, graph[i][0]);
            if (parent1 == parent2) return false;
            for (int j: graph[i]) {
                int parentj = unionHelper(root, j);
                if (parentj == parent1) return false;
                root[parentj] = parent2;
            }
        }
        return true;
    }
    
    int unionHelper(vector<int> & root, int i) {
        while (i != root[i]) {
            root[i] = root[root[i]];
            i = root[i];
        }
        return i;
    }   
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值