前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode 886. 可能的二分法(着色DFS/BFS/拓展并查集)

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

作者头像
Michael阿明
发布2020-07-13 15:04:30
3380
发布2020-07-13 15:04:30
举报

1. 题目

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

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

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

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

示例 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

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一样,实现形式不一样而已
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 并查集

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

  • 把并查集大小开到2倍的N,左边是自己的颜色,右边是自己不喜欢的另一种颜色
  • 当a,b互斥时,a 与 b 对应的相反颜色 b+N 应该是一致的,进行merge(a, b+N)
  • 同理,merge(b, a+N)
在这里插入图片描述
在这里插入图片描述
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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目
  • 2. 解题
    • 2.1 DFS
      • 2.2 BFS
        • 2.3 并查集
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档