LC-2493.将节点分成尽可能多的组

题目描述

leetcode 困难题

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

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

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

  • 图中每个节点都只属于一个组。
  • 图中每条边连接的两个点 [ai, bi] ,如果 ai 属于编号为 x 的组,bi 属于编号为 y 的组,那么 |y - x| = 1 。
    请你返回最多可以将节点分为多少个组(也就是最大的 m )。如果没办法在给定条件下分组,请你返回 -1 。

示例1:

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

提示1:

1
2
3
4
5
6
1 <= n <= 500
1 <= edges.length <= 10^4
edges[i].length == 2
1 <= ai, bi <= n
ai != bi
两个点之间至多只有一条边。

二分图判定 + BFS

一个结论是如果一个图能够按照题意进行划分,必然是一个二分图。所以可以先跑一遍二分图判定,如果非二分图直接返回即可。

然后再考虑如何得出最大组数。先考虑连通块内的划分,题目中的划分要求其实等价于 $bfs$ 中同一层的节点需要划分到同一组,所以我们枚举每个点作为起点进行 $bfs$ ,$bfs$ 过程中的最大深度就为该连通块所能划分的最大组数。而为了让组数尽量多,我们让不同连通块之间划分到不同组,那么不同连通块能够划分的组数相加即为答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Solution {
private List<Integer>[] g;
private int[] color;

public int magnificentSets(int n, int[][] edges) {
color = new int[n];
g = (List<Integer>[])(new List[n + 1]);
Arrays.setAll(g, i -> new ArrayList<>());
for(int[] e : edges){
g[e[0] - 1].add(e[1] - 1);
g[e[1] - 1].add(e[0] - 1);
}
int ans = 0;
for(int i = 0; i < n; i++){
if(color[i] != 0){
continue;
}
List<Integer> connect = new ArrayList<>();
if(!dfs(i, 1, connect)){
return -1;
}
ans += connect.stream().mapToInt(this::bfs).max().orElseThrow();
}
return ans;
}

private boolean dfs(int p, int curColor, List<Integer> connect){
connect.add(p);
color[p] = curColor;
for(int item : g[p]){
if((color[item] ^ curColor) == 0){
return false;
}
if(color[item] != 0){
continue;
}
if(!dfs(item, 3 ^ curColor, connect)){
return false;
}
}
return true;
}

private int bfs(int p){
int maxDepth = 0;
boolean[] visit = new boolean[color.length];
Deque<int[]> queue = new ArrayDeque<>();
queue.offer(new int[]{p, 1});
visit[p] = true;
while(!queue.isEmpty()){
int[] top = queue.poll();
maxDepth = Math.max(maxDepth, top[1]);
for(int item : g[top[0]]){
if(visit[item]){
continue;
}
visit[item] = true;
queue.offer(new int[]{item, top[1] + 1});
}
}
return maxDepth;
}
}

LC-2493.将节点分成尽可能多的组
https://wecgwm.github.io/2023/03/06/LC-2493-将节点分成尽可能多的组/
作者
yichen
发布于
2023年3月6日
许可协议