class Solution {
public:
int magnificentSets(int n, vector<vector<int>>& edges) {
}
};
2493. 将节点分成尽可能多的组
给你一个正整数 n
,表示一个 无向 图中的节点数目,节点编号从 1
到 n
。
同时给你一个二维整数数组 edges
,其中 edges[i] = [ai, bi]
表示节点 ai
和 bi
之间有一条 双向 边。注意给定的图可能是不连通的。
请你将图划分为 m
个组(编号从 1 开始),满足以下要求:
[ai, bi]
,如果 ai
属于编号为 x
的组,bi
属于编号为 y
的组,那么 |y - x| = 1
。请你返回最多可以将节点分为多少个组(也就是最大的 m
)。如果没办法在给定条件下分组,请你返回 -1
。
示例 1:
输入: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
原站题解
golang 解法, 执行用时: 116 ms, 内存消耗: 7.3 MB, 提交时间: 2023-04-02 12:33:51
func magnificentSets(n int, edges [][]int) (ans int) { g := make([][]int, n) for _, e := range edges { x, y := e[0]-1, e[1]-1 g[x] = append(g[x], y) g[y] = append(g[y], x) } time := make([]int, n) // 充当 vis 数组的作用(避免在 BFS 内部重复创建 vis 数组) clock := 0 bfs := func(start int) (depth int) { // 返回从 start 出发的最大深度 clock++ time[start] = clock for q := []int{start}; len(q) > 0; depth++ { tmp := q q = nil for _, x := range tmp { for _, y := range g[x] { if time[y] != clock { // 没有在同一次 BFS 中访问过 time[y] = clock q = append(q, y) } } } } return } colors := make([]int8, n) var nodes []int var isBipartite func(int, int8) bool isBipartite = func(x int, c int8) bool { // 二分图判定,原理见视频讲解 nodes = append(nodes, x) colors[x] = c for _, y := range g[x] { if colors[y] == c || colors[y] == 0 && !isBipartite(y, -c) { return false } } return true } for i, c := range colors { if c == 0 { nodes = nil if !isBipartite(i, 1) { // 如果不是二分图(有奇环),则无法分组 return -1 } // 否则一定可以分组 maxDepth := 0 for _, x := range nodes { // 枚举连通块的每个点,作为起点 BFS,求最大深度 maxDepth = max(maxDepth, bfs(x)) } ans += maxDepth } } return } func max(a, b int) int { if b > a { return b }; return a }
cpp 解法, 执行用时: 276 ms, 内存消耗: 48.6 MB, 提交时间: 2023-04-02 12:33:39
class Solution { public: int magnificentSets(int n, vector<vector<int>> &edges) { vector<vector<int>> g(n); for (auto &e : edges) { int x = e[0] - 1, y = e[1] - 1; g[x].push_back(y); g[y].push_back(x); } int time[n], clock = 0; // time 充当 vis 数组的作用(避免在 BFS 内部重复创建 vis 数组) memset(time, 0, sizeof(time)); auto bfs = [&](int start) -> int { // 返回从 start 出发的最大深度 int depth = 0; time[start] = ++clock; vector<int> q = {start}; while (!q.empty()) { vector<int> nxt; for (int x : q) for (int y : g[x]) if (time[y] != clock) { // 没有在同一次 BFS 中访问过 time[y] = clock; nxt.push_back(y); } q = move(nxt); ++depth; } return depth; }; int8_t color[n]; memset(color, 0, sizeof(color)); vector<int> nodes; function<bool(int, int8_t)> is_bipartite = [&](int x, int8_t c) -> bool { // 二分图判定,原理见视频讲解 nodes.push_back(x); color[x] = c; for (int y : g[x]) if (color[y] == c || color[y] == 0 && !is_bipartite(y, -c)) return false; return true; }; int ans = 0; for (int i = 0; i < n; ++i) { if (color[i]) continue; nodes.clear(); if (!is_bipartite(i, 1)) return -1; // 如果不是二分图(有奇环),则无法分组 // 否则一定可以分组 int max_depth = 0; for (int x : nodes) // 枚举连通块的每个点,作为起点 BFS,求最大深度 max_depth = max(max_depth, bfs(x)); ans += max_depth; } return ans; } };
java 解法, 执行用时: 267 ms, 内存消耗: 45 MB, 提交时间: 2023-04-02 12:33:25
class Solution { private List<Integer>[] g; private final List<Integer> nodes = new ArrayList<>(); private int[] time, color; // time 充当 vis 数组的作用(避免在 BFS 内部重复创建 vis 数组) private int clock; public int magnificentSets(int n, int[][] edges) { g = new ArrayList[n]; Arrays.setAll(g, e -> new ArrayList<>()); for (var e : edges) { int x = e[0] - 1, y = e[1] - 1; g[x].add(y); g[y].add(x); } time = new int[n]; color = new int[n]; var ans = 0; for (var i = 0; i < n; i++) { if (color[i] != 0) continue; nodes.clear(); if (!isBipartite(i, 1)) return -1; // 如果不是二分图(有奇环),则无法分组 // 否则一定可以分组 var maxDepth = 0; for (var x : nodes) // 枚举连通块的每个点,作为起点 BFS,求最大深度 maxDepth = Math.max(maxDepth, bfs(x)); ans += maxDepth; } return ans; } // 二分图判定,原理见视频讲解 private boolean isBipartite(int x, int c) { nodes.add(x); color[x] = c; for (var y : g[x]) if (color[y] == c || color[y] == 0 && !isBipartite(y, -c)) return false; return true; } // 返回从 start 出发的最大深度 private int bfs(int start) { var depth = 0; time[start] = ++clock; var q = new ArrayList<Integer>(); q.add(start); while (!q.isEmpty()) { var tmp = q; q = new ArrayList<>(); for (var x : tmp) for (var y : g[x]) if (time[y] != clock) { // 没有在同一次 BFS 中访问过 time[y] = clock; q.add(y); } ++depth; } return depth; } }
python3 解法, 执行用时: 1072 ms, 内存消耗: 18 MB, 提交时间: 2023-04-02 12:33:13
class Solution: def magnificentSets(self, n: int, edges: List[List[int]]) -> int: g = [[] for _ in range(n)] for x, y in edges: g[x - 1].append(y - 1) g[y - 1].append(x - 1) time = [0] * n # 充当 vis 数组的作用(避免在 BFS 内部重复创建 vis 数组) clock = 0 def bfs(start: int) -> int: # 返回从 start 出发的最大深度 depth = 0 nonlocal clock clock += 1 time[start] = clock q = [start] while q: tmp = q q = [] for x in tmp: for y in g[x]: if time[y] != clock: # 没有在同一次 BFS 中访问过 time[y] = clock q.append(y) depth += 1 return depth color = [0] * n def is_bipartite(x: int, c: int) -> bool: # 二分图判定,原理见视频讲解 nodes.append(x) color[x] = c for y in g[x]: if color[y] == c or color[y] == 0 and not is_bipartite(y, -c): return False return True ans = 0 for i, c in enumerate(color): if c: continue nodes = [] if not is_bipartite(i, 1): return -1 # 如果不是二分图(有奇环),则无法分组 # 否则一定可以分组 ans += max(bfs(x) for x in nodes) # 枚举连通块的每个点,作为起点 BFS,求最大深度 return ans