树形dp:
需要解决的问题,他的数据结构是树
acwing 树的最长路径
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
现在请你找到树中的一条最长路径。
换句话说,要找到一条路径,使得使得路径两端的点的距离最远。
注意:路径中可以只包含一个点。
输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。
输出格式
输出一个整数,表示树的最长路径的长度。
思路:
树形dp,一般是由子节点来推出父节点
题中要求的是,所有路径中的最大路径
那么可以把经过父节点的所有路径归到父节点上
现在求经过父节点的所有路径中的最大
1.最大路径是一条到子节点的路径
2.最大路径是从一个子节点经过父节点到另一个子节点的路径
解决方法,保存所有值,保存最大值和次小值,由这2个值就可以求出第二种情况
因为有负的,不过题中说了一个点也可以,所以最小值是0,故答案一开始赋值为0
#include <cstring>
#include <iostream>
using namespace std;
const int N = 200010;
int h[N],ne[N],val[N],w[N],idx;
int res = 0;
void add(int a,int b,int c)
{
val[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++;
}
int dfs(int u,int fa)
{
int d1,d2;
d1 = d2 = 0;
for(int i = h[u];~ i;i = ne[i])
{
int j = val[i];
if(j == fa) continue;
int d = dfs(j,u) + w[i];
if(d >= d1) d2 = d1,d1 = d;
else if(d > d2) d2 = d;
}
res = max(res,d1 + d2);
return d1;
}
int main()
{
int n;
cin >> n;
memset(h,-1,sizeof h);
for(int i = 1;i < n;i ++)
{
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
add(b,a,c);
}
dfs(1,-1);
cout << res << endl;
return 0;
}
acwing 树的中心
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。
输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。
输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。
思路:
题中要求出,一个点,他到离他最远的点的距离最小
也就先要求出来所有点到离它最远的点的距离,然后取个最小值
因为树形dp,一般是子节点更新父节点
所以,可以把每一个节点看成一个父节点,求出由父节点开始的所有路径中最大值
首先求出往子节点走的最大值,也就是上题的做法
然后考虑往父节点的父节点走的方法
2种情况:
父节点的父节点他往下走的最大值就是走到这个点来的
那么它要往上走的话,就可以往它父节点的次大值那边走,或者继续往上走
父节点的父节点往下走的最大值不是走到这个点来的
那么它就可以往最大值那边走,或者继续往上走
最后求出每个点往下和往上的最大值,再取个最小值
#include <iostream>
#include <cstring>
using namespace std;
const int N = 20010;
int ne[N],h[N],val[N],w[N],idx;
int n;
int d1[N],d2[N],up[N],p1[N],p2[N];
void add(int a,int b,int c)
{
val[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++;
}
int dfs(int u,int fa)
{
for(int i = h[u];~ i;i = ne[i])
{
int j = val[i];
if(j == fa) continue;
int d = dfs(j,u) + w[i];
if(d >= d1[u]) d2[u] = d1[u],d1[u] = d,p1[u] = j;
else if(d > d2[u]) d2[u] = d,p2[u] = j;
}
return d1[u];
}
void f(int u,int fa)
{
for(int i = h[u];~ i;i = ne[i])
{
int j = val[i];
if(j == fa) continue;
if(p1[u] == j) up[j] = max(d2[u],up[u]) + w[i];
else up[j] = max(d1[u],up[u]) + w[i];
f(j,u);
}
}
int main()
{
cin >> n;
memset(h,-1,sizeof h);
for(int i = 1;i < n;i ++)
{
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
add(b,a,c);
}
dfs(1,-1);
f(1,-1);
int res = 0x3f3f3f3f;
for(int i = 1;i <= n;i ++) res = min(res,max(d1[i],up[i]));
cout << res << endl;
return 0;
}