LeetCode 886. 可能的二分法(着色DFS/BFS/拓展并查集)

2020-07-13 15:04:30 浏览数 (1)

1. 题目

给定一组 N 人(编号为 1, 2, …, N), 我们想把每个人分进任意大小的两组。

每个人都可能不喜欢其他人,那么他们不应该属于同一组。

形式上,如果 dislikes[i] = [a, b],表示不允许将编号为 a 和 b 的人归入同一组。

当可以用这种方法将每个人分进两组时,返回 true;否则返回 false。

代码语言:javascript复制
示例 1:
输入:N = 4, dislikes = [[1,2],[1,3],[2,4]]
输出:true
解释:group1 [1,4], group2 [2,3]

示例 2:
输入:N = 3, dislikes = [[1,2],[1,3],[2,3]]
输出:false

示例 3:
输入:N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出:false
 
提示:
1 <= N <= 2000
0 <= dislikes.length <= 10000
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
对于 dislikes[i] == dislikes[j] 不存在 i != j 

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/possible-bipartition 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

  • 把人分成2组,组内没有自己不喜欢的人

2.1 DFS

着色法,初始颜色均为0,着色成1或者2,遇到矛盾的返回 false

代码语言:javascript复制
class Solution {
	unordered_map<int,unordered_set<int>> m;
	bool ans = true;
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
    	if(dislikes.size() <= 2) return true;
    	vector<int> color(N 1, 0);
    	for(auto& d : dislikes)//建图
    	{
    		m[d[0]].insert(d[1]);
    		m[d[1]].insert(d[0]);
    	}
    	for(int i = 1; i <= N; i  )
    	{
    		if(color[i] == 0)//未着色的
    		{
    			color[i] = 1;//着色为1
    			dfs(i, 1, color);
    			if(!ans)
    				return false;
    		}
    	}
    	return true;
    }
    void dfs(int id, int col, vector<int> &color)
    {
    	if(!ans) return;
    	int nextcol = col==1 ? 2 : 1;//跟我相连的(不喜欢的人)颜色相反
    	for(auto it = m[id].begin(); it != m[id].end(); it  )
    	{
    		if(color[*it] == col)//颜色相同,出错
    			ans = false;
    		if(color[*it] == 0)//没有访问过的,继续着色
	    	{
	    		color[*it] = nextcol;
	    		dfs(*it, nextcol, color);
	    	}
    	}
    }
};

528 ms 71.3 MB

2.2 BFS

  • 思路跟dfs一样,实现形式不一样而已
代码语言:javascript复制
class Solution {
	unordered_map<int,unordered_set<int>> m;
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
    	if(dislikes.size() <= 2) return true;
    	vector<int> color(N 1, 0);
    	for(auto& d : dislikes)//建图
    	{
    		m[d[0]].insert(d[1]);
    		m[d[1]].insert(d[0]);
    	}
        queue<int> q;
        int id, col = 1, nextcol, size;
    	for(int i = 1; i <= N; i  )
    	{
    		if(color[i] == 0)//未访问的
    		{
    			color[i] = 1;//着色为1
                col = 1;
    			q.push(i);
                while(!q.empty())
                {
                    size = q.size();
                    nextcol = col==1 ? 2 : 1;//下一层颜色需要变
                    while(size--)
                    {
                        id = q.front();
                        q.pop();
                        for(auto it = m[id].begin(); it != m[id].end(); it  )
                        {	//相连的,不喜欢的,颜色不能一样
                            if(color[*it] == col)
                                return false;
                            if(color[*it] == 0)
                            {
                                color[*it] = nextcol;//没访问的,不喜欢的,颜色跟我不一样
                                q.push(*it);
                            }
                        }
                    }
                    col = col==1? 2 : 1;//换颜色
                }
    		}
    	}
    	return true;
    }
};

524 ms 70.9 MB

2.3 并查集

  • 参考 数据结构–并查集(Disjoint-Set)

参考了题解区大佬们的思路

  • 把并查集大小开到2倍的N,左边是自己的颜色,右边是自己不喜欢的另一种颜色
  • 当a,b互斥时,a 与 b 对应的相反颜色 b N 应该是一致的,进行merge(a, b N)
  • 同理,merge(b, a N)
代码语言:javascript复制
class dsu
{
	vector<int> f;
public:
	dsu(int n)
	{
		f.resize(n 1);
		for(int i = 0; i < n 1;   i)
			f[i] = i;
	}
	void merge(int a, int b)
	{
		int fa = find(a), fb = find(b);
		f[fa] = fb;
	}
	int find(int a)//循环 路径压缩
	{
        int origin = a;
		while(a != f[a])
			a = f[a];
		return f[origin] = a;//路径压缩
	}
};
class Solution {
public:
    bool possibleBipartition(int N, vector<vector<int>>& dislikes) {
    	if(dislikes.size() <= 2) return true;
    	dsu u(2*N 1);
        int a, b, da, db;
        for(auto& d : dislikes)
    	{
    		a = d[0];
            b = d[1];
            da = a N;//a的另外一种颜色
            db = b N;//b的另外一种颜色
            if(u.find(a) == u.find(b))
                return false;
            u.merge(a,db);//a跟b互斥,那么a跟b的反是一样的颜色
            u.merge(b,da);//同理
    	}
        return true;
    }
};

256 ms 39.6 MB

0 人点赞