树的直径学习笔记(DFS)

树的直径

  1. 什么是树的直径?
    树的直径指树中最远的两个节点之间的距离,连接这两个节点之间的路径被称为树的最长链
  2. 树的直径的时间复杂度?
    \(O(N)\)
  3. 原理
    我们通过两次DFS,第一次从任一点\(S\)出发进行DFS,找到一个离\(S\)最远的点\(D\),然后从\(D\)点出发,寻找离\(D\)点最远的点\(E\),\(D\)\(E\)之间的距离即为树的直径。
  4. 原理证明?
    分三种情况
    第一种,\(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\)是直径矛盾,所以这种情况也不成立
  5. 代码实现
#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好多少,所以不介绍了(其实还是因为太弱没看懂

posted @ 2020-12-06 11:31  面包络合物  阅读(160)  评论(0编辑  收藏  举报