树的直径学习笔记(DFS)
树的直径
- 什么是树的直径?
树的直径指树中最远的两个节点之间的距离,连接这两个节点之间的路径被称为树的最长链。 - 树的直径的时间复杂度?
\(O(N)\) - 原理
我们通过两次DFS,第一次从任一点\(S\)出发进行DFS,找到一个离\(S\)最远的点\(D\),然后从\(D\)点出发,寻找离\(D\)点最远的点\(E\),\(D\)\(E\)之间的距离即为树的直径。 - 原理证明?
分三种情况
第一种,\(P\)在直径上,根据定义可知\(PQ\)为树的直径
第二种,\(P\)不在直径上
我们使用反证法
假设\(PQ\)不是直径,但\(AB\)是直径,则\(OP+OQ>OP+OB\),得\(OQ+OA>OB+OA\),即\(QA>AB\),与直径定义相悖,故原命题成立
第三种,\(PQ\)与\(AB\)无交点
依旧是反证法,\(MP+MQ>MQ+MN+NB\),同时减掉\(MQ\),得\(MP>MN+NB\),易知\(MP+MN>NB\),所以\(MP+MN+NA>NB+NA\),
即\(MP+MN+NA>AB\),与\(AB\)是直径矛盾,所以这种情况也不成立 - 代码实现
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7;
int n,m,tot = 0;
bool v[N];
int ans = 0,farp;
int ver[N],edge[N],Next[N],head[N],d[N];
void add(int x,int y,int z)
{
ver[++tot] = y;
edge[tot] = z;
Next[tot] = head[x];
head[x] = tot;
}
void dfs(int x)
{
for(int i = head[x];i;i = Next[i])
{
int y = ver[i];
int z = edge[i];
if(v[y]) continue;
v[y] = 1;
d[y] = d[x] + z;
dfs(y);
}
}
int main()
{
int x,y,z;
cin >> n >> m;
for(int i = 1;i <= m;i ++ )
{
cin >> x >> y >> z;
add(x,y,z);
add(y,x,z);
}
dfs(1);
for(int i = 1;i <= n;i ++ )
{
if(d[i] > ans) ans = d[i],farp;
d[i] = v[i] = 0;
}
ans = 0;
dfs(farp);
for(int i = 1;i <= n;i ++ )
{
if(d[i] > ans) ans = d[i];
}
cout << ans << endl;
return 0;
}
至于为什么不学树形DP的方法,因为树形DP无法记录最长链经过的结点,时间复杂度上又不比DFS好多少,所以不介绍了(其实还是因为太弱没看懂
流萤断续光,一明一灭一尺间