main
黄海 2 years ago
parent 56bdbe7669
commit 15c93d1456

@ -1,47 +0,0 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = N << 1;
int n; // n个结点
// 链式前向星
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// 换根dp模板
int ans; // 答案,直径
int d1[N], d2[N]; // d1[i],d2[i]:经过i点的最长,次长长度是多少
bool st[N]; // 是不是遍历过了
void dfs(int u) {
st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (st[v]) continue; // v点访问过了
// 走v子树,完成后v子树中每个节点的d1[v],d2[v]都已经准备好u节点可以直接利用
dfs(v);
// w[i]:u->v的路径长度,d1[u]:最长路径,d2[u]:次长路径
if (d1[v] + w[i] >= d1[u]) // v可以用来更新u的最大值
d2[u] = d1[u], d1[u] = d1[v] + w[i]; // 最长路转移
else if (d1[v] + w[i] > d2[u])
d2[u] = d1[v] + w[i]; // 次长路转移
}
// 更新结果
ans = max(ans, d1[u] + d2[u]);
}
int main() {
cin >> n;
memset(h, -1, sizeof h); // 初始化邻接表
for (int i = 1; i < n; i++) { // n-1条边
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c); // 换根dp一般用于无向图
}
dfs(1); // 任选一个点作为根节点,此处选择的是肯定存在的1号结点
cout << ans << endl;
return 0;
}

@ -40,14 +40,14 @@ $10^5≤c_i≤10^5$
### 二、朴素版本$dfs$【不能$AC$】
朴素$dfs$: 对每个点求最远点最大距离, 所有结果的$max$就是结果.
通过 $10/16$. 然后$TLE$, 效果不是很理想。
通过 $11/17$. 然后$TLE$, 效果不是很理想。
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
//  暴力搜索,从每个节点为根出发,遍历整根树,找出距离自己的最大距离,然后每个最大距离取min
// 10/16,其它TLE,无法AC
// 11/17,其它TLE,无法AC
int n;
int ans; // 树的直径
// 邻接表
@ -55,15 +55,13 @@ int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int st[N];
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
if (sum > ans) ans = 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]);
}
}
@ -79,10 +77,7 @@ int main() {
}
// 多次dfs,是TLE的罪魁祸首
for (int i = 1; i <= n; i++) {
memset(st, 0, sizeof st);
dfs(i, 0);
}
for (int i = 1; i <= n; i++) dfs(i, 0, 0);
// 输出结果
printf("%d", ans);
@ -105,14 +100,14 @@ int main() {
![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/%7Byear%7D/%7Bmonth%7D/%7Bmd5%7D.%7BextName%7D/20230605133953.png)
通过了 $14/16$个数据,剩余两个测试点,居然是$WA$,真是,唉~
通过了 $15/17$个数据,剩余两个测试点,居然是$WA$,真是,唉~
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
int ans; // 保存最长路径
int t; // 保存找到的最远点
@ -123,18 +118,16 @@ int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int st[N];
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
if (sum > ans) {
ans = sum; // 记录最大距离
t = u; // 记录最远的点t1
}
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]);
}
}
@ -146,11 +139,9 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
memset(st, 0, sizeof st);
dfs(1, 0); // 先找到点距离点1最远的点t1
dfs(1, 0, 0); // 先找到点距离点1最远的点t1
memset(st, 0, sizeof st);
dfs(t, 0); // 找到距离点t1->t2最远的点t1
dfs(t, 0, 0); // 找到距离点t1->t2最远的点t1
printf("%d", ans);
return 0;
@ -194,50 +185,47 @@ int main() {
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = N << 1;
int n; // n个结点
const int N = 10010; // 点数上限
const int M = N * 2; // 边数上限
int n;
int ans;
int d1[N], d2[N]; // 最长,次长
int st[N];
// 链式前向星
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u) {
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (st[j]) continue;
// 走j子树,完成后j子树中每个节点的d1[j],d2[j]都已经准备好u节点可以直接利用
dfs(j);
int ans; // 答案,直径
int mx1[N], mx2[N]; // mx1[i],mx2[i]:经过i点的最长,次长长度是多少
// d1[u]:最长路径,d2[u]:次长路径
if (d1[j] + w[i] >= d1[u])
d2[u] = d1[u], d1[u] = d1[j] + w[i]; // 最长路转移
else if (d1[j] + w[i] > d2[u])
d2[u] = d1[j] + w[i]; // 次长路转移
void dfs(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == fa) continue; // v点访问过了
// 走v子树,完成后v子树中每个节点的mx1[v],mx2[v]都已经准备好u节点可以直接利用
dfs(v, u);
// w[i]:u->v的路径长度,mx1[u]:最长路径,mx2[u]:次长路径
int x = mx1[v] + w[i];
if (mx1[u] <= x) // v可以用来更新u的最大值
mx2[u] = mx1[u], mx1[u] = x; // 最长路转移
else if (mx2[u] < x)
mx2[u] = x; // 次长路转移
}
// 更新结果
ans = max(ans, d1[u] + d2[u]);
ans = max(ans, mx1[u] + mx2[u]);
}
int main() {
cin >> n;
// 初始化邻接表
memset(h, -1, sizeof h);
for (int i = 1; i < n; i++) {
memset(h, -1, sizeof h); // 初始化邻接表
for (int i = 1; i < n; i++) { // n-1
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
add(a, b, c), add(b, a, c); // 换根dp一般用于无向图
}
// 任选一个点作为根节点
dfs(1);
// 输出答案
printf("%d", ans);
dfs(1, 0); // 任选一个点作为根节点,此处选择的是肯定存在的1号结点
cout << ans << endl;
return 0;
}
```

@ -1,9 +1,9 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
//  暴力搜索,从每个节点为根出发,遍历整根树,找出距离自己的最大距离,然后每个最大距离取min
// 10/16,其它TLE,无法AC
// 11/17,其它TLE,无法AC
int n;
int ans; // 树的直径
// 邻接表
@ -11,15 +11,13 @@ int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int st[N];
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
if (sum > ans) ans = 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]);
}
}
@ -35,10 +33,7 @@ int main() {
}
// 多次dfs,是TLE的罪魁祸首
for (int i = 1; i <= n; i++) {
memset(st, 0, sizeof st);
dfs(i, 0);
}
for (int i = 1; i <= n; i++) dfs(i, 0, 0);
// 输出结果
printf("%d", ans);

@ -2,7 +2,7 @@
using namespace std;
const int N = 10010, M = 20010;
const int N = 10010, M = N << 1;
int ans; // 保存最长路径
int t; // 保存找到的最远点
@ -13,18 +13,16 @@ int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int st[N];
void dfs(int u, int sum) {
st[u] = 1;
void dfs(int u, int fa, int sum) {
if (sum > ans) {
ans = sum; // 记录最大距离
t = u; // 记录最远的点t1
}
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]);
}
}
@ -36,11 +34,9 @@ int main() {
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
memset(st, 0, sizeof st);
dfs(1, 0); // 先找到点距离点1最远的点t1
dfs(1, 0, 0); // 先找到点距离点1最远的点t1
memset(st, 0, sizeof st);
dfs(t, 0); // 找到距离点t1->t2最远的点t1
dfs(t, 0, 0); // 找到距离点t1->t2最远的点t1
printf("%d", ans);
return 0;

@ -0,0 +1,46 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = N << 1;
int n; // n个结点
// 链式前向星
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int ans; // 答案,直径
int mx1[N], mx2[N]; // mx1[i],mx2[i]:经过i点的最长,次长长度是多少
void dfs(int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == fa) continue; // v点访问过了
// 走v子树,完成后v子树中每个节点的mx1[v],mx2[v]都已经准备好u节点可以直接利用
dfs(v, u);
// w[i]:u->v的路径长度,mx1[u]:最长路径,mx2[u]:次长路径
int x = mx1[v] + w[i];
if (mx1[u] <= x) // v可以用来更新u的最大值
mx2[u] = mx1[u], mx1[u] = x; // 最长路转移
else if (mx2[u] < x)
mx2[u] = x; // 次长路转移
}
// 更新结果
ans = max(ans, mx1[u] + mx2[u]);
}
int main() {
cin >> n;
memset(h, -1, sizeof h); // 初始化邻接表
for (int i = 1; i < n; i++) { // n-1条边
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c); // 换根dp一般用于无向图
}
dfs(1, 0); // 任选一个点作为根节点,此处选择的是肯定存在的1号结点
cout << ans << endl;
return 0;
}
Loading…
Cancel
Save