树的直径的一道很经典的题目
因为这个题巧妙的把两种求树的直径的做法都体现的淋漓尽致
- 我先来介绍一下树的直径吧:
- 在一棵树里,每一条边都有权值(树里面两个点之间的边权),那么树上最远的距离就为树的直径,当然我们大多数做的都是边权为1的树,这个时候也就是树上距离最远的两个点
- 求解树的直径的两种方法
- 1.树形DP
- ans 来记录树的直径的长度,那么ans是怎么记录的呢?dist[i]表示从节点出发可以到达的最远的距离
- 对于一个节点x,dist[x]是x节点可以到达的最远的距离(也就是最长链的距离),y是x的一个子节点,那么dist[x]是否小于 dist[y] + ver[x][y]呢
- 那么答案是有可能的,那么这个时候dist[x]链就变成了次长链的距离,ans = 应该为当前节点的最长链长度+当前节点的次长链的长度。首先x的最长链的长度为dist[x],而经过从y的这个节点延申的链的长度+ver[x][y]大于dist[x],那么dist[x]就次长链,而当时的次长链(假设为dist[z] + ver[x][z]),就变成了次次长链;之前的 ans = dist[x] + dist[z] + ver[z][x],那么此时的ans = dist[y] + ver[x][y] + dist[x]
- 所以ans = max(ans,dist[x] + dist[y] + ver[x][y] ),并且我们还得让dist[x]为最长链的长度
- dist[x] = max(dist[x],dist[y] + ver[x][y])
- 看一下代码吧~
/*
这里我用的vector来存储的边和距离
原型为: vector<pair<int,int>>v[N]
st数组的原型为bool st[N]
dist的原型为 dist[N]
*/
void dp(int u)
{
dist[u] = 0;
for(auto &x : v[u])
{
int j = x.first,w = x.second;
if(st[j])continue;
st[j] = true;
dp(j);
ans = max(ans,dist[j] + w + dist[u]);
dist[u] = max(dist[u],dist[j] + w);
}
}
//或者是这个代码,原理一样,就是把st数组换成了fa来判断
void dp(int u,int fa)
{
dist[u] = 0;
for(auto &x : v[u])
{
int j = x.first,w = x.second;
if(j == fa)continue;
dp(j,u);
l2 = max(l2,dist[j] + w + dist[u]);
dist[u] = max(dist[u],dist[j] + w);
}
}