树的直径
概念
树上任意两节点之间最⻓的简单路径即为树的直径。
⼀棵树可以有多条直径,他们的⻓度相等。
性质
若树上所有边的边权均为正,则树的所有直径的中点重合。
结论⼀:不同直径之间⼀定会相交⽽不会相离。
因此,所有直径都是两两相交的。
推论:所有直径的公共边⼀定是连续的。
实现
两次dfs
在⼀棵树上,从任意节点x 开始进⾏⼀次dfs,找到距离x 最远的结点必定为直径的⼀端。
如果存在负边权,上述性质将不再成⽴。因此,两次dfs只适⽤于所有边权全部⾮负的情况。
//从任意结点x开始进行第一次dfs,找到距离x最远的结点y;
//然后再从y结点开始再来一次dfs,找到距离y最远的结点z;
//y~z就是直径的两端
int n;
vector<PII> edges[N];
int d[N], maxd, r;
int pre[N]; // 记录直径所在的路线
void dfs(int x, int fa){
pre[x] = fa;
if(d[x] > maxd) maxd = d[x], r = x;
for(auto& t : edges[x]){
int y = t.first, z = t.second;
if(y == fa) continue;
d[y] = d[x] + z;
dfs(y, x);
}
}
void fun(){
dfs(1, 0); maxd = d[r] = 0;
dfs(r, 0);
for(int i = r; i; i = pre[i]) cout << i << " ";
cout << endl;
cout << maxd << endl;
}
局限性:不能求带负边权的直径
优越性:可以求出直径的路径
树形dp
int n;
vector<PII> edges[N];
int f[N], ret;
void dfs(int x, int fa)
{
for(auto& t : edges[x]){
int y = t.first, z = t.second;
if(y == fa) continue;
dfs(y, x);
ret = max(ret, f[x] + f[y] + z);
f[x] = max(f[x], f[y] + z);
}
}
void fun(){
dfs(1, 0);
cout << ret << endl;
}

浙公网安备 33010602011771号