From 15c93d14560a77f10478d16706e09a35e4def79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Wed, 17 Jan 2024 10:27:05 +0800 Subject: [PATCH] 'commit' --- .../AcWing_TiGao/T3/HuanGenDp/1072_dfs_3.cpp | 47 --------- .../T3 => Topic}/HuanGenDp/1072.eddx | Bin .../T3 => Topic}/HuanGenDp/1072.md | 94 ++++++++---------- .../T3 => Topic}/HuanGenDp/1072_dfs_1.cpp | 19 ++-- .../T3 => Topic}/HuanGenDp/1072_dfs_2.cpp | 18 ++-- TangDou/Topic/HuanGenDp/1072_dfs_3.cpp | 46 +++++++++ .../T3 => Topic}/HuanGenDp/1073.md | 0 .../T3 => Topic}/HuanGenDp/1073_1.cpp | 0 .../T3 => Topic}/HuanGenDp/1073_2.cpp | 0 9 files changed, 101 insertions(+), 123 deletions(-) delete mode 100644 TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_3.cpp rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1072.eddx (100%) rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1072.md (76%) rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1072_dfs_1.cpp (68%) rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1072_dfs_2.cpp (63%) create mode 100644 TangDou/Topic/HuanGenDp/1072_dfs_3.cpp rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1073.md (100%) rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1073_1.cpp (100%) rename TangDou/{AcWing_TiGao/T3 => Topic}/HuanGenDp/1073_2.cpp (100%) diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_3.cpp b/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_3.cpp deleted file mode 100644 index 5837a69..0000000 --- a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_3.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include - -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; -} \ No newline at end of file diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072.eddx b/TangDou/Topic/HuanGenDp/1072.eddx similarity index 100% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1072.eddx rename to TangDou/Topic/HuanGenDp/1072.eddx diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072.md b/TangDou/Topic/HuanGenDp/1072.md similarity index 76% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1072.md rename to TangDou/Topic/HuanGenDp/1072.md index 01618bb..45f4006 100644 --- a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072.md +++ b/TangDou/Topic/HuanGenDp/1072.md @@ -40,14 +40,14 @@ $−10^5≤c_i≤10^5$ ### 二、朴素版本$dfs$【不能$AC$】 朴素$dfs$: 对每个点求最远点最大距离, 所有结果的$max$就是结果. -通过 $10/16$. 然后$TLE$, 效果不是很理想。 +通过 $11/17$. 然后$TLE$, 效果不是很理想。 ```cpp {.line-numbers} #include 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 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 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; } ``` diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_1.cpp b/TangDou/Topic/HuanGenDp/1072_dfs_1.cpp similarity index 68% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_1.cpp rename to TangDou/Topic/HuanGenDp/1072_dfs_1.cpp index 9352ef9..152dbdb 100644 --- a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_1.cpp +++ b/TangDou/Topic/HuanGenDp/1072_dfs_1.cpp @@ -1,9 +1,9 @@ #include 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); diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_2.cpp b/TangDou/Topic/HuanGenDp/1072_dfs_2.cpp similarity index 63% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_2.cpp rename to TangDou/Topic/HuanGenDp/1072_dfs_2.cpp index df42655..162a573 100644 --- a/TangDou/AcWing_TiGao/T3/HuanGenDp/1072_dfs_2.cpp +++ b/TangDou/Topic/HuanGenDp/1072_dfs_2.cpp @@ -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; diff --git a/TangDou/Topic/HuanGenDp/1072_dfs_3.cpp b/TangDou/Topic/HuanGenDp/1072_dfs_3.cpp new file mode 100644 index 0000000..18419d3 --- /dev/null +++ b/TangDou/Topic/HuanGenDp/1072_dfs_3.cpp @@ -0,0 +1,46 @@ +#include + +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; +} \ No newline at end of file diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1073.md b/TangDou/Topic/HuanGenDp/1073.md similarity index 100% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1073.md rename to TangDou/Topic/HuanGenDp/1073.md diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1073_1.cpp b/TangDou/Topic/HuanGenDp/1073_1.cpp similarity index 100% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1073_1.cpp rename to TangDou/Topic/HuanGenDp/1073_1.cpp diff --git a/TangDou/AcWing_TiGao/T3/HuanGenDp/1073_2.cpp b/TangDou/Topic/HuanGenDp/1073_2.cpp similarity index 100% rename from TangDou/AcWing_TiGao/T3/HuanGenDp/1073_2.cpp rename to TangDou/Topic/HuanGenDp/1073_2.cpp