1072. 树的最长路径 - AcWing题库
给定一棵树,树中包含 n n n 个结点(编号 1 − n 1 -n 1−n)和 n − 1 n−1 n−1条无向边,每条边都有一个权值。
现在请你找到树中的一条最长路径。
换句话说,要找到一条路径,使得使得路径两端的点的距离最远。
注意:路径中可以只包含一个点。
也就是求树的直径,对于无边权树来说,可以先求出距离任意点最远点,然后求出最远点的最长路径,即为树的直径。有边权的一般情况,可以求出所有挂在高点上的路径,最长的就是直径。
输入格式
第一行包含整数
n
n
n。
接下来 n−1n−1n-1 行,每行包含三个整数 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示点 a i 和 b i a_i和b_i ai和bi之间存在一条权值为 c i c_i ci的边。
输出格式
输出一个整数,表示树的最长路径的长度。
数据范围
1
≤
n
≤
10000
1≤n≤10000
1≤n≤10000
1
≤
a
i
,
b
i
≤
n
1≤a_i,b_i≤n
1≤ai,bi≤n
1
≤
c
i
≤
1
0
5
1≤c_i≤10^5
1≤ci≤105
输入样例:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出样例:
22
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
const int N = 100010;
const int M = N;
int h[N], e[M], ne[M], idx, w[M];
int ans = 0;
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int dfs(int u, int fa)
{
int dist = 0;//表示从当前点往下走的最大长度
int d1 = 0, d2 = 0;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
int d = dfs(j, u) + w[i];
dist = max(dist, d);
if(d >= d1) d2 = d1, d1 = d;
else if(d > d2) d2 = d;
}
ans = max(ans, d1 + d2);
return dist;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n - 1; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
dfs(1, -1);
cout << ans << endl;
}
1073. 树的中心 - AcWing题库
给定一棵树,树中包含 n n n 个结点(编号 1 − n 1-n 1−n)和 n − 1 n−1 n−1条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。
求出所有点的向下走的最长路径,然后求出向上走的最长路径,也就是点1不回到点2的最长路径
因此要求出d1、d2、up和p1(去往d1的节点,防止1回到2)这样就可以找到树的中心
输入格式
第一行包含整数 n n n。
接下来 n − 1 n−1 n−1 行,每行包含三个整数 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示点 a i 和 b i a_i和b_i ai和bi之间存在一条权值为 c i c_i ci的边。
输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。
数据范围
1
≤
n
≤
10000
1≤n≤10000
1≤n≤10000
1
≤
a
i
,
b
i
≤
n
1≤a_i,b_i≤n
1≤ai,bi≤n
1
≤
c
i
≤
1
0
5
1≤c_i≤10^5
1≤ci≤105
输入样例:
5
2 1 1
3 2 1
4 3 1
5 1 1
输出样例:
2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2 * 10000;
const int M = N;
const int inf = 1e9;
int n;
int h[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N], up[N], p1[N], p2[N];
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int dfs_d(int u, int fa)
{
d1[u] = d2[u] = -inf;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
int d = dfs_d(j, u) + w[i];
if(d >= d1[u])
{
d2[u] = d1[u], d1[u] = d;
p2[u] = p1[u], p1[u] = j;
}
else if(d > d2[u]) d2[u] = d, p2[u] = j;
}
if(d1[u] == -inf) d1[u] = d2[u] = 0;
return d1[u];
}
void dfs_u(int u, int fa)
{
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
if(p1[u] == j) up[j] = max(up[u], d2[u]) + w[i];
else up[j] = max(up[u], d1[u]) + w[i];
dfs_u(j, u);
}
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);add(b, a, c);
}
dfs_d(1, -1);
dfs_u(1, -1);
int ans = inf;
for(int i = 1; i <= n; i ++ ) ans = min(ans, max(d1[i], up[i]));
cout << ans;
}
1075. 数字转换 - AcWing题库
父亲节点只有一个,就是他的约数和
- 使用筛法求出所有点的父亲节点
- 连接父亲节点子节点,并判断根节点(森林)
- 求出最长路径
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 55000;
const int M = 2 * N;
int f[N];
int h[N], e[M], w[M], ne[M], idx;
bool st[N];
int n;
int ans = 0;
void add(int a, int b) // 添加一条边a->b
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int dfs(int u, int fa)
{
int d1 = 0, d2 = 0;
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
int d = dfs(j, u) + 1;
if(d >= d1) d2 = d1, d1 = d;
else if(d >= d2) d2 = d;
}
ans = max(ans, d1 + d2);
return d1;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n / 2; i++ )
for(int j = 2; j <= n / i; j ++ )
{
f[i * j] += i;// i 是 i * j 的约数
}
for(int i = 1; i <= n; i ++ )
{
if(f[i] < i && f[i] > 0)
{
add(f[i], i);
st[i] = true; //找到父亲节点。
}
}
for(int i = 1; i <= n; i ++ )
if(!st[i]) dfs(i, -1);//寻找最长路径
cout << ans;
}