难度:Hard
标签:位运算;图论;Floyd算法
链接: https://leetcode.cn/problems/number-of-possible-sets-of-closing-branches/
题目中给出的n范围为1 <= n <= 10
,那么说明最多的10个分部的情况下,可以选择关闭的可行情况有2^10
种,这个数据量并不大,可以用暴力枚举做出来。
但是如何知道选择了哪些顶点呢?这里有用到位运算这个很巧妙的方法,一个int型数据有32位,我们最多只要用其中的10位即可表示所有的情况,同时还能用每一位来表示是否选择了某一个顶点(分部)。
利用Floyd算法可以求解出一个图中任意两个顶点之间的最小距离。当我们选择一个可能的集合时,判断这个集合中有的分部之间的最短距离是否会大于题目要求的最远距离maxDistance
,如果有大于的,说明有分部之间最短的距离都无法满足要求。
需要注意的是,每一种情况我们只需要处理在集合中包含的分部。
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
| 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& r : roads) { int x = r[0], y = r[1], w = r[2]; g[x][y] = min(g[x][y], w); g[y][x] = min(g[y][x], w); } vector<vector<int>> f(n); auto check = [&](int set) { for (int i = 0; i < n; i++) { if ((set >> i) & 1) { f[i] = g[i]; } }
for (int k = 0; k < n; k++) { if (((set >> k) & 1) == 0) continue; for (int i = 0; i < n; i++) { if (((set >> i) & 1) == 0) continue; for (int j = 0; j < n; j++) { if (((set >> j) & 1) == 0) continue; f[i][j] = min(f[i][j], f[i][k] + f[k][j]); } } }
for (int i = 0; i < n; i++) { if (((set >> i) & 1) == 0) continue; for (int j = 0; j < n; j++) { if (((set >> j) & 1) && f[i][j] > maxDistance) { return false; } } } return true; }; int res = 0; for (int i = 0; i < (1 << n); i++) { res += check(i); } return res; } };
|