main
黄海 2 years ago
parent c1460f1413
commit e3d22e2098

@ -43,11 +43,10 @@ $1≤c_i≤10^5$
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
int n;
int ans;
int res = INF;
int st[N];
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
@ -55,14 +54,13 @@ void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
dfs(j, sum + w[i]);
int v = e[i];
if (v == fa) continue;
dfs(v, u, sum + w[i]);
}
if (sum > ans) ans = sum;
ans = max(ans, sum);
}
int main() {
@ -73,10 +71,10 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
// 暴力换根
for (int i = 1; i <= n; i++) {
ans = 0;
memset(st, 0, sizeof st);
dfs(i, 0);
dfs(i, 0, 0);
res = min(res, ans);
}
printf("%d\n", res);
@ -92,7 +90,7 @@ int main() {
同样,先来想一下如何暴力求解该问题:先 **枚举** 目标节点,然后求解该节点到其他节点的 **最远距离**
时间复杂度为 $O(n^2)$,对于本题的 **数据规模**,十分极限,经测试只能过 $6/10$
时间复杂度为 $O(n^2)$,对于本题的 **数据规模**,十分极限,经测试只能过 $7/11$
#### 考虑如何优化求解该问题的方法
思考一下:在确定树的 **拓扑结构** 后单独求一个节点的 **最远距离** 时,会在该树上去比较哪些 **路径** 呢?
@ -139,17 +137,15 @@ $up[u]$:存下$u$节点向上走的最长路径的长度
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
const int M = N << 1;
const int N = 10010, M = N << 1;
const int INF = 0x3f3f3f3f;
int n;
int n; // n个节点
int mx1[N]; // mx1[u]u节点向下走的最长路径的长度
int mx2[N]; // mx2[u]u节点向下走的次长路径的长度
int id[N]; // id[u]u节点向下走的最长路径是从哪一个节点下去的
int up[N]; // up[u]u节点向上走的最长路径的长度
int d1[N]; // d1[u]存下u节点向下走的最长路径的长度
int d2[N]; // d2[u]存下u节点向下走的次长路径的长度
int p1[N]; // p1[u]存下u节点向下走的最长路径是从哪一个节点下去的
int up[N]; // up[u]存下u节点向上走的最长路径的长度
int st[N];
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
@ -157,39 +153,35 @@ void add(int a, int b, int c = 0) {
}
// 功能:以u为根向叶子进行递归利用子节点返回的最长信息更新自己的最长和次长,并记录最长是从哪个节点来的
void dfs1(int u) {
st[u] = 1;
void dfs1(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
int v = e[i];
if (v == fa) continue;
// 递归完才能有数据
dfs1(j);
if (d1[j] + w[i] >= d1[u]) { // 更新最长
d2[u] = d1[u]; // ① 更新次长,必须在第一位因为下面d1[u]会被改写
d1[u] = d1[j] + w[i]; // ② 更新最长
p1[u] = j; // ③ 记录最长来源
} else if (d1[j] + w[i] > d2[u]) // 更新次长
d2[u] = d1[j] + w[i];
dfs1(v, u);
int x = mx1[v] + w[i]; // u问到儿子v可以带我走多远
if (mx1[u] < x) { //
mx2[u] = mx1[u]; // ① 更新次长
mx1[u] = x; // ② 更新最长
id[u] = v; // ③ 记录最长来源
} else if (mx2[u] < x) //
mx2[u] = x;
}
}
// 功能:完成向上的信息填充
void dfs2(int u) {
st[u] = 1;
void dfs2(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
// 三者取其一
up[j] = w[i] + up[u];
if (p1[u] == j)
up[j] = max(up[j], w[i] + d2[u]);
int v = e[i];
if (v == fa) continue;
// 二者取其一
if (id[u] == v)
up[v] = max(mx2[u], up[u]) + w[i];
else
up[j] = max(up[j], w[i] + d1[u]);
// 准备好了信息,再进入递归
dfs2(j);
up[v] = max(mx1[u], up[u]) + w[i];
// 递归
dfs2(v, u);
}
}
@ -201,13 +193,11 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
memset(st, 0, sizeof st);
dfs1(1); // 选择任意一个节点进行dfs,用儿子更新父亲的统计信息
memset(st, 0, sizeof st);
dfs2(1); // 向上
dfs1(1, 0); // 选择任意一个节点进行dfs,用儿子更新父亲的统计信息
dfs2(1, 0); // 向上
int res = INF;
for (int i = 1; i <= n; i++) res = min(res, max(d1[i], up[i]));
for (int i = 1; i <= n; i++) res = min(res, max(mx1[i], up[i]));
printf("%d\n", res);
return 0;
@ -247,6 +237,3 @@ void dfs1(int u) {
// if (d1[u] == -INF) d1[u] = d2[u] = 0; //特判叶子结点
}
```
### 四、下一步需研读
https://blog.csdn.net/weixin_44232130/article/details/116567482
https://www.cnblogs.com/hxxO-o/p/16558801.html

@ -2,11 +2,10 @@
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
int n;
int ans;
int res = INF;
int st[N];
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
@ -14,14 +13,13 @@ void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
dfs(j, sum + w[i]);
int v = e[i];
if (v == fa) continue;
dfs(v, u, sum + w[i]);
}
if (sum > ans) ans = sum;
ans = max(ans, sum);
}
int main() {
@ -32,10 +30,10 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
// 暴力换根
for (int i = 1; i <= n; i++) {
ans = 0;
memset(st, 0, sizeof st);
dfs(i, 0);
dfs(i, 0, 0);
res = min(res, ans);
}
printf("%d\n", res);

@ -1,17 +1,15 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
const int M = N << 1;
const int N = 10010, M = N << 1;
const int INF = 0x3f3f3f3f;
int n;
int n; // n个节点
int mx1[N]; // mx1[u]u节点向下走的最长路径的长度
int mx2[N]; // mx2[u]u节点向下走的次长路径的长度
int id[N]; // id[u]u节点向下走的最长路径是从哪一个节点下去的
int up[N]; // up[u]u节点向上走的最长路径的长度
int d1[N]; // d1[u]存下u节点向下走的最长路径的长度
int d2[N]; // d2[u]存下u节点向下走的次长路径的长度
int p1[N]; // p1[u]存下u节点向下走的最长路径是从哪一个节点下去的
int up[N]; // up[u]存下u节点向上走的最长路径的长度
int st[N];
// 邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
@ -19,39 +17,35 @@ void add(int a, int b, int c = 0) {
}
// 功能:以u为根向叶子进行递归利用子节点返回的最长信息更新自己的最长和次长,并记录最长是从哪个节点来的
void dfs1(int u) {
st[u] = 1;
void dfs1(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
int v = e[i];
if (v == fa) continue;
// 递归完才能有数据
dfs1(j);
if (d1[j] + w[i] >= d1[u]) { // 更新最长
d2[u] = d1[u]; // ① 更新次长,必须在第一位因为下面d1[u]会被改写
d1[u] = d1[j] + w[i]; // ② 更新最长
p1[u] = j; // ③ 记录最长来源
} else if (d1[j] + w[i] > d2[u]) // 更新次长
d2[u] = d1[j] + w[i];
dfs1(v, u);
int x = mx1[v] + w[i]; // u问到儿子v可以带我走多远
if (mx1[u] < x) { // 更新最长
mx2[u] = mx1[u]; // ① 更新次长
mx1[u] = x; // ② 更新最长
id[u] = v; // ③ 记录最长来源
} else if (mx2[u] < x) // 更新次长
mx2[u] = x;
}
}
// 功能:完成向上的信息填充
void dfs2(int u) {
st[u] = 1;
void dfs2(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
// 三者取其一
up[j] = w[i] + up[u];
if (p1[u] == j)
up[j] = max(up[j], w[i] + d2[u]);
int v = e[i];
if (v == fa) continue;
// 二者取其一
if (id[u] == v)
up[v] = max(mx2[u], up[u]) + w[i];
else
up[j] = max(up[j], w[i] + d1[u]);
// 准备好了信息,再进入递归
dfs2(j);
up[v] = max(mx1[u], up[u]) + w[i];
// 递归
dfs2(v, u);
}
}
@ -63,13 +57,11 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
memset(st, 0, sizeof st);
dfs1(1); // 选择任意一个节点进行dfs,用儿子更新父亲的统计信息
memset(st, 0, sizeof st);
dfs2(1); // 向上
dfs1(1, 0); // 选择任意一个节点进行dfs,用儿子更新父亲的统计信息
dfs2(1, 0); // 向上
int res = INF;
for (int i = 1; i <= n; i++) res = min(res, max(d1[i], up[i]));
for (int i = 1; i <= n; i++) res = min(res, max(mx1[i], up[i]));
printf("%d\n", res);
return 0;

@ -1193,7 +1193,9 @@ signed main() {
for (int i = 1; i <= n; i++) cout << g[i] - max(up[i], mx1[i]) << endl;
}
```
#### [$AcWing$ $1073$. 树的中心](https://www.cnblogs.com/littlehb/p/15786805.html)
#### [$AcWing$ $1148$ 秘密的牛奶运输](https://www.cnblogs.com/littlehb/p/16054005.html)
#### [$CF708C$ $Centroids$](https://www.luogu.com.cn/problem/CF708C)
@ -1208,6 +1210,3 @@ https://www.cnblogs.com/DongPD/p/17498336.html
https://blog.csdn.net/Emm_Titan/article/details/123875298
#### [$AcWing$ $1073$. 树的中心](https://www.cnblogs.com/littlehb/p/15786805.html)
#### [$AcWing$ $1148$ 秘密的牛奶运输](https://www.cnblogs.com/littlehb/p/16054005.html)
Loading…
Cancel
Save