100140. 关闭分部的可行集合数目
一个公司在全国有 n
个分部,它们之间有的有道路连接。一开始,所有分部通过这些道路两两之间互相可以到达。
公司意识到在分部之间旅行花费了太多时间,所以它们决定关闭一些分部(也可能不关闭任何分部),同时保证剩下的分部之间两两互相可以到达且最远距离不超过 maxDistance
。
两个分部之间的 距离 是通过道路长度之和的 最小值 。
给你整数 n
,maxDistance
和下标从 0 开始的二维整数数组 roads
,其中 roads[i] = [ui, vi, wi]
表示一条从 ui
到 vi
长度为 wi
的 无向 道路。
请你返回关闭分部的可行方案数目,满足每个方案里剩余分部之间的最远距离不超过 maxDistance
。
注意,关闭一个分部后,与之相连的所有道路不可通行。
注意,两个分部之间可能会有多条道路。
示例 1:
输入:n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]] 输出:5 解释:可行的关闭分部方案有: - 关闭分部集合 [2] ,剩余分部为 [0,1] ,它们之间的距离为 2 。 - 关闭分部集合 [0,1] ,剩余分部为 [2] 。 - 关闭分部集合 [1,2] ,剩余分部为 [0] 。 - 关闭分部集合 [0,2] ,剩余分部为 [1] 。 - 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。 总共有 5 种可行的关闭方案。
示例 2:
输入:n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]] 输出:7 解释:可行的关闭分部方案有: - 关闭分部集合 [] ,剩余分部为 [0,1,2] ,它们之间的最远距离为 4 。 - 关闭分部集合 [0] ,剩余分部为 [1,2] ,它们之间的距离为 2 。 - 关闭分部集合 [1] ,剩余分部为 [0,2] ,它们之间的距离为 2 。 - 关闭分部集合 [0,1] ,剩余分部为 [2] 。 - 关闭分部集合 [1,2] ,剩余分部为 [0] 。 - 关闭分部集合 [0,2] ,剩余分部为 [1] 。 - 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。 总共有 7 种可行的关闭方案。
示例 3:
输入:n = 1, maxDistance = 10, roads = [] 输出:2 解释:可行的关闭分部方案有: - 关闭分部集合 [] ,剩余分部为 [0] 。 - 关闭分部集合 [0] ,关闭后没有剩余分部。 总共有 2 种可行的关闭方案。
提示:
1 <= n <= 10
1 <= maxDistance <= 105
0 <= roads.length <= 1000
roads[i].length == 3
0 <= ui, vi <= n - 1
ui != vi
1 <= wi <= 1000
原站题解
golang 解法, 执行用时: 34 ms, 内存消耗: 6.9 MB, 提交时间: 2024-07-17 19:52:21
func numberOfSets(n, maxDistance int, roads [][]int) int { g := make([][]int, n) for i := range g { g[i] = make([]int, n) for j := range g[i] { g[i][j] = math.MaxInt / 2 // 防止加法溢出 } } for _, e := range roads { x, y, wt := e[0], e[1], e[2] g[x][y] = min(g[x][y], wt) g[y][x] = min(g[y][x], wt) } ans := 1 // s=0 一定满足要求 f := make([][][]int, 1<<n) for i := range f { f[i] = make([][]int, n) for j := range f[i] { f[i][j] = make([]int, n) for k := range f[i][j] { f[i][j][k] = math.MaxInt / 2 } } } f[0] = g for s := uint(1); s < 1<<n; s++ { k := bits.TrailingZeros(s) t := s ^ (1 << k) ok := true for i := 0; i < n; i++ { for j := 0; j < n; j++ { f[s][i][j] = min(f[t][i][j], f[t][i][k]+f[t][k][j]) if ok && j < i && s>>i&1 != 0 && s>>j&1 != 0 && f[s][i][j] > maxDistance { ok = false } } } if ok { ans++ } } return ans }
java 解法, 执行用时: 25 ms, 内存消耗: 44.2 MB, 提交时间: 2024-07-17 19:52:05
class Solution { public int numberOfSets(int n, int maxDistance, int[][] roads) { int[][] g = new int[n][n]; for (int[] row : g) { Arrays.fill(row, Integer.MAX_VALUE / 2); } for (int[] e : roads) { int x = e[0]; int y = e[1]; int wt = e[2]; g[x][y] = Math.min(g[x][y], wt); g[y][x] = Math.min(g[y][x], wt); } int ans = 1; // s=0 一定满足要求 int[][][] f = new int[1 << n][n][n]; for (int[][] matrix : f) { for (int[] row : matrix) { Arrays.fill(row, Integer.MAX_VALUE / 2); } } f[0] = g; for (int s = 1; s < (1 << n); s++) { int k = Integer.numberOfTrailingZeros(s); int t = s ^ (1 << k); boolean ok = true; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { f[s][i][j] = Math.min(f[t][i][j], f[t][i][k] + f[t][k][j]); if (ok && j < i && (s >> i & 1) != 0 && (s >> j & 1) != 0 && f[s][i][j] > maxDistance) { ok = false; } } } ans += ok ? 1 : 0; } return ans; } }
python3 解法, 执行用时: 564 ms, 内存消耗: 18.7 MB, 提交时间: 2024-07-17 19:51:44
class Solution: def numberOfSets(self, n: int, maxDistance: int, roads: List[List[int]]) -> int: g = [[inf] * n for _ in range(n)] for x, y, wt in roads: g[x][y] = min(g[x][y], wt) g[y][x] = min(g[y][x], wt) ans = 1 # s=0 一定满足要求 f = [[[inf] * n for _ in range(n)] for _ in range(1 << n)] f[0] = g for s in range(1, 1 << n): k = s.bit_length() - 1 t = s ^ (1 << k) ok = 1 for i in range(n): for j in range(n): f[s][i][j] = min(f[t][i][j], f[t][i][k] + f[t][k][j]) # 手动求 min 可以更快 if ok and j < i and s >> i & 1 and s >> j & 1 and f[s][i][j] > maxDistance: ok = 0 ans += ok return ans
cpp 解法, 执行用时: 164 ms, 内存消耗: 17.8 MB, 提交时间: 2023-12-11 17:27:16
class Solution { public: int numberOfSets(int n, int maxDistance, vector<vector<int>> &roads) { vector<vector<int>> g(n, vector<int>(n, INT_MAX / 2)); // 防止加法溢出 for (int i = 0; i < n; i++) { g[i][i] = 0; } for (auto &e: roads) { int x = e[0], y = e[1], wt = e[2]; g[x][y] = min(g[x][y], wt); g[y][x] = min(g[y][x], wt); } vector<vector<int>> f(n); auto check = [&](int s) -> bool { for (int i = 0; i < n; i++) { if ((s >> i) & 1) { f[i] = g[i]; } } // Floyd for (int k = 0; k < n; k++) { if (((s >> k) & 1) == 0) continue; for (int i = 0; i < n; i++) { if (((s >> i) & 1) == 0) continue; for (int j = 0; j < n; j++) { f[i][j] = min(f[i][j], f[i][k] + f[k][j]); } } } for (int i = 0; i < n; i++) { if (((s >> i) & 1) == 0) continue; for (int j = 0; j < n; j++) { if ((s >> j) & 1 && f[i][j] > maxDistance) { return false; } } } return true; }; int ans = 0; for (int s = 0; s < (1 << n); s++) { // 枚举子集 ans += check(s); } return ans; } };
java 解法, 执行用时: 22 ms, 内存消耗: 40.6 MB, 提交时间: 2023-12-11 17:26:58
class Solution { public int numberOfSets(int n, int maxDistance, int[][] roads) { int[][] g = new int[n][n]; // 领接矩阵 for (int i = 0; i < n; i++) { Arrays.fill(g[i], Integer.MAX_VALUE / 2); // 防止加法溢出 g[i][i] = 0; } for (int[] e : roads) { int x = e[0], y = e[1], wt = e[2]; g[x][y] = Math.min(g[x][y], wt); g[y][x] = Math.min(g[y][x], wt); } int ans = 0; int[][] f = new int[n][n]; next: for (int s = 0; s < (1 << n); s++) { for (int i = 0; i < n; i++) { if ((s >> i & 1) == 1) { System.arraycopy(g[i], 0, f[i], 0, n); } } // Floyd for (int k = 0; k < n; k++) { if ((s >> k & 1) == 0) continue; for (int i = 0; i < n; i++) { if ((s >> i & 1) == 0) continue; for (int j = 0; j < n; j++) { f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j]); } } } for (int i = 0; i < n; i++) { if ((s >> i & 1) == 0) continue; for (int j = 0; j < n; j++) { if ((s >> j & 1) == 1 && f[i][j] > maxDistance) { continue next; } } } ans++; } return ans; } }
golang 解法, 执行用时: 20 ms, 内存消耗: 2.8 MB, 提交时间: 2023-12-11 17:26:02
// 二进制枚举 + floyd 算法 func numberOfSets(n, maxDistance int, roads [][]int) (ans int) { g := make([][]int, n) for i := range g { g[i] = make([]int, n) for j := range g[i] { if j != i { // g[i][i] = 0 g[i][j] = math.MaxInt / 2 // 防止加法溢出 } } } for _, e := range roads { x, y, wt := e[0], e[1], e[2] g[x][y] = min(g[x][y], wt) g[y][x] = min(g[y][x], wt) } f := make([][]int, n) for i := range f { f[i] = make([]int, n) } next: for s := 0; s < 1<<n; s++ { // 枚举子集 for i, row := range g { if s>>i&1 == 0 { continue } copy(f[i], row) } // Floyd for k := range f { if s>>k&1 == 0 { continue } for i := range f { if s>>i&1 == 0 { continue } for j := range f { f[i][j] = min(f[i][j], f[i][k]+f[k][j]) } } } for i, di := range f { if s>>i&1 == 0 { continue } for j, dij := range di { if s>>j&1 > 0 && dij > maxDistance { continue next } } } ans++ } return }
python3 解法, 执行用时: 1832 ms, 内存消耗: 16.1 MB, 提交时间: 2023-12-11 17:25:08
class Solution: def numberOfSets(self, n: int, maxDistance: int, roads: List[List[int]]) -> int: g = [[inf] * n for _ in range(n)] for i in range(n): g[i][i] = 0 for x, y, wt in roads: g[x][y] = min(g[x][y], wt) g[y][x] = min(g[y][x], wt) f = [None] * n def check(s: int) -> int: for i, row in enumerate(g): if s >> i & 1: f[i] = row[:] # Floyd for k in range(n): if (s >> k & 1) == 0: continue for i in range(n): if (s >> i & 1) == 0: continue for j in range(n): f[i][j] = min(f[i][j], f[i][k] + f[k][j]) for i, di in enumerate(f): if (s >> i & 1) == 0: continue for j, dij in enumerate(di): if s >> j & 1 and dij > maxDistance: return 0 return 1 return sum(check(s) for s in range(1 << n)) # 枚举子集