6256. 将节点分成尽可能多的组

2022/12/04 leetcode 共 2077 字,约 6 分钟

title

problem link

给你一个正整数 n ,表示一个 无向 图中的节点数目,节点编号从 1 到 n 。

同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 双向 边。注意给定的图可能是不连通的。

请你将图划分为 m 个组(编号从 1 开始),满足以下要求:

  • 图中每个节点都只属于一个组。
  • 图中每条边连接的两个点 [ai, bi] ,如果 ai 属于编号为 x 的组,bi 属于编号为 y 的组,那么 |y - x| = 1 。

请你返回最多可以将节点分为多少个组(也就是最大的 m )。如果没办法在给定条件下分组,请你返回 -1 。

示例 1:

img

输入:n = 6, edges = [[1,2],[1,4],[1,5],[2,6],[2,3],[4,6]]
输出:4
解释:如上图所示,
- 节点 5 在第一个组。
- 节点 1 在第二个组。
- 节点 2 和节点 4 在第三个组。
- 节点 3 和节点 6 在第四个组。
所有边都满足题目要求。
如果我们创建第五个组,将第三个组或者第四个组中任何一个节点放到第五个组,至少有一条边连接的两个节点所属的组编号不符合题目要求。

示例 2:

输入:n = 3, edges = [[1,2],[2,3],[3,1]]
输出:-1
解释:如果我们将节点 1 放入第一个组,节点 2 放入第二个组,节点 3 放入第三个组,前两条边满足题目要求,但第三条边不满足题目要求。
没有任何符合题目要求的分组方式。

提示:

  • 1 <= n <= 500
  • 1 <= edges.length <= 104
  • edges[i].length == 2
  • 1 <= ai, bi <= n
  • ai != bi
  • 两个点之间至多只有一条边。

solution

二分图才可以分组 / 也可以通过bfs后,比较和start点距离判断,a<->b, 则dis[a]!=dis[b]才可以分组

class Graph:
    def bfs(graph, start):
        '''
        :param graph: collection.defaultdict(list)
        :param start: start point
        :return:
        '''
        q = collections.deque()
        q.append(start)
        visit = set()
        visit.add(start)
        level = 0
        while len(q):
            level += 1
            for _ in range(len(q)):
                u = q.popleft()
                for v in graph[u]:
                    if v not in visit:
                        visit.add(v)
                        q.append(v)
        return visit, level
    '''
    划分连同分量, 返回每个联通分量的点list,可以多个联通分量
    '''
    def groups(self, points, graph) -> List[List[int]]:
        groups = []
        total_visit = set()
        for i in points:
            visit = set()
            def dfs(u):
                nonlocal visit
                visit.add(u)
                for v in graph[u]:
                    if v not in visit:
                        dfs(v)

            if i not in total_visit:
                dfs(i)
            if visit:
                for l in visit:
                    total_visit.add(l)
                groups.append(list(visit))
        return groups

    # 判断是否是二分图,input可以是多个子连通图。graph: 链接表
    def isBipartite(self, graph) -> bool:
        ans = True
        color = collections.defaultdict(int)
        n = len(graph)

        def dfs(i):
            nonlocal ans
            if not ans:
                return
            if color[i] == 0:
                color[i] = 1
            cur = color[i]
            for neighbor in graph[i]:
                if color[neighbor] == cur:
                    ans = False
                    break
                if color[neighbor] == 0:
                    color[neighbor] = 2 if cur == 1 else 1
                    dfs(neighbor)

        for i in range(n):
            if color[i] == 0:
                dfs(i)
        # print(color)
        return ans

class Solution:
    def magnificentSets(self, n: int, edges: List[List[int]]) -> int:
        graph = collections.defaultdict(list)
        for u, v in edges:
            graph[u].append(v)
            graph[v].append(u)
        # 二分图才可以分组
        if not Graph().isBipartite(graph):
            return -1
        # 划分联通分量
        groups = Graph().groups(range(1, n + 1), graph)
        ans = 0
        for group in groups:
            t = 0
            # 对联通分量的每个节点用bfs求最大长度
            for i in group:
                t = max(t, Graph.bfs(graph, i)[1])
            ans += t
        return ans

Search

    Table of Contents