ARST打卡第201周[201/521]

Algorithm

lc1617_统计子树中城市之间最大距离

自己思考:
边长为1,
多少边,多少个相邻为1的城市间距
一条大于等于3个点的n点的线上,n-2为相邻为2的城市间距
因此n点线上,n-1为相邻为1的城市间距
所以想到的作法是梳理所有的线:
然后每条线去累加n-1,n-2…到各个d的数组

所有的度为1的点相互握手就是所有的边
所以:

  1. 输入过程计算点的度
  2. 度为一的点握手计算边长
  3. 每个边长把n-1,n-2,n-3…依次填入

等等,那示例1中的3个点的有交集点的城市群怎么处理呢?

看了题解的三种方法:
由于图中的节点数 n 的取值范围为 1≤n≤16,我们采用状态压缩的思想,用二进制掩码 mask 来表示图中的一个子树,枚举所有可能的子树,并检测该子树的连通性。

反思自己为啥没想出来: 没有想清楚n不超过16就是遍历所有树的意思

方法二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
// bfs版本
class Solution {
public:
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
vector<vector<int>> adj(n);
for (auto &edge : edges) {
int x = edge[0] - 1;
int y = edge[1] - 1;
adj[x].emplace_back(y);
adj[y].emplace_back(x);
}

function<int(int, int, int)> dfs = [&](int parent, int u, int mask)->int {
int depth = 0;
for (int v : adj[u]) {
if (v != parent && mask & (1 << v)) {
depth = max(depth, 1 + dfs(u, v, mask));
}
}
return depth;
};

vector<int> ans(n - 1);
for (int i = 1; i < (1 << n); i++) {
int x = 32 - __builtin_clz(i) - 1;
int mask = i;
int y = -1;
queue<int> qu;
qu.emplace(x);
mask &= ~(1 << x);
while (!qu.empty()) {
y = qu.front();
qu.pop();
for (int vertex : adj[y]) {
if (mask & (1 << vertex)) {
mask &= ~(1 << vertex);
qu.emplace(vertex);
}
}
}
if (mask == 0) {
int diameter = dfs(-1, y, i);
if (diameter > 0) {
ans[diameter - 1]++;
}
}
}
return ans;
}
};
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
// 动态规划版
class Solution {
public:
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
vector<vector<int>> adj(n);
for (auto &edge : edges) {
int x = edge[0] - 1;
int y = edge[1] - 1;
adj[x].emplace_back(y);
adj[y].emplace_back(x);
}
function<int(int, int&, int&)> dfs = [&](int root, int& mask, int& diameter)->int {
int first = 0, second = 0;
// 减去城市群里面自身的标记,这是bfs去检测子树连通性
mask &= ~(1 << root);
for (int vertex : adj[root]) {
if (mask & (1 << vertex)) {
mask &= ~(1 << vertex);
int distance = 1 + dfs(vertex, mask, diameter);
if (distance > first) {
second = first;
first = distance;
} else if (distance > second) {
second = distance;
}
}
}
diameter = max(diameter, first + second);
return first;
};

vector<int> ans(n - 1);
for (int i = 1; i < (1 << n); i++) {
int root = 32 - __builtin_clz(i) - 1;
int mask = i;
int diameter = 0;
dfs(root, mask, diameter);
if (mask == 0 && diameter > 0) {
ans[diameter - 1]++;
}
}
return ans;
}
};
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
// 枚举任意两点直径,题解
class Solution {
public:
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
vector<vector<int>> adj(n);
vector<vector<int>> dist(n, vector<int>(n, INT_MAX));
for (auto &edge : edges) {
int x = edge[0] - 1;
int y = edge[1] - 1;
adj[x].emplace_back(y);
adj[y].emplace_back(x);
dist[x][y] = dist[y][x] = 1;
}
for (int i = 0; i < n; i++) {
dist[i][i] = 0;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
if (dist[j][i] != INT_MAX && dist[i][k] != INT_MAX) {
dist[j][k] = min(dist[j][k], dist[j][i] + dist[i][k]);
}
}
}
}
function<int(int, int, int, int)> dfs = [&](int u, int parent, int x, int y) -> int {
if (dist[u][x] > dist[x][y] || dist[u][y] > dist[x][y]) {
return 1;
}
if ((dist[u][y] == dist[x][y] && u < x) || (dist[u][x] == dist[x][y] && u < y)) {
return 1;
}
int ret = 1;
for (int v : adj[u]) {
if (v != parent) {
ret *= dfs(v, u, x, y);
}
}
if (dist[u][x] + dist[u][y] > dist[x][y]) {
ret++;
}
return ret;
};
vector<int> ans(n - 1);
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
ans[dist[i][j] - 1] += dfs(i, -1, i, j);
}
}
return ans;
}
};

Review

我们是否需要别人的赞美才能快乐?自由选择的勇气

斯多葛主义哲学,当我们重新思考名誉和利益,我们降低预期,回归本源的水,食物,休息等的满足的时候,
我们将会获得失去的勇气,被讨厌的勇气,和去尝试做自己喜欢的一切事情的自由选择的勇气

Tips

pbRPC快速使用三部曲

Share

10个漂亮的VSCode浅色(Light)主题

强烈推荐Snazzy Light,超舒服超美,推荐理由:

  1. light比dark更护眼,所以决定从dark转到light
  2. 不适应一般light的配色不够鲜艳,但是Snazzy Light配色很鲜艳,让我无缝从dark转换过来而不觉得色彩单调