886. 可能的二分法(Python)

难度:★★★☆☆
类型:图
方法:深度优先搜索

力扣链接请移步本题传送门
更多力扣中等题的解决方案请移步力扣中等题目录

题目

给定一组 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
dislikes[i].length == 2
1 <= dislikes[i][j] <= N
dislikes[i][0] < dislikes[i][1]
对于 dislikes[i] == dislikes[j] 不存在 i != j

解答

图的问题常用深度优先搜索解决。

首先我们把不喜欢关系转化成更加便于遍历的邻接表的形式,也就是说,对于每一个结点,都有一个对应的列表,这个列表中包含这个结点不喜欢的结点。

定义深度优先搜索函数dfs,函数的输入是一个结点node,以及颜色c(True或False两种),函数的返回值是布尔值,表达的含义是是否将结点node染色成c成功,函数的功能是对结点node进行染色,并根据不喜欢关系将node结点所有不喜欢的结点染成相反色。

函数开头直接输入跳出条件,即如果该结点node已经被染色成,那么就要判断被染成的颜色是否是c,如果是,说明染色成功,否则染色失败。

如果node结点没有被染色,我们将该结点染色成c,并研究该结点所有不喜欢的结点,并将这些结点染色成相反色,如果都能成功染色成相反色,则返回True,只要有一个染色失败,则返回False。

我们可以用一个字典阿里记录每个结点被染成的颜色,两个颜色实际上代表了两个阵营。

最后,我们要逐个结点的研究,如果当前结点尚未被染色,则使用深度优先搜索的办法将该结点及其联通结点(不喜欢关系建立的连通域)进行染色,否则,不考虑当前已经被染色的结点。因为我们是一个连通域一个连通域来考虑的,注意这里的联通域是用不喜欢关系建立起来的。只有所有连通域都校验通过,才能说能够成功分成两个阵营。

from collections import defaultdict


class Solution(object):
    def possibleBipartition(self, N, dislikes):
        graph = defaultdict(list)
        for u, v in dislikes:
            graph[u].append(v)
            graph[v].append(u)

        color = {}

        def dfs(node, our_flag=0):
            if node in color:                       # 已经被染过色
                return color[node] == our_flag
            color[node] = our_flag
            return all(dfs(dislike, not our_flag) for dislike in graph[node])

        for node in range(1, N+1):
            if node not in color and not dfs(node):
                return False
        return True

如有疑问或建议,欢迎评论区留言~

有关更多力扣中等题的python解决方案,请移步力扣中等题解析

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容