zoukankan      html  css  js  c++  java
  • 树的直径和证明

    (以下阐述部分借鉴)
    博客1
    博客2

    概念

    树的直径:2点距离最远的路径.

    结论

    先说结论,对于一颗无根树,首先随便找一个点(u)开始进行搜索,找到离当前点最远的一点(s),然后从(s)开始搜最远的点(t)树的直径就为(s-t)

    Ⅰ两遍(dfs||bfs)

    证明
    找到直径,我们只需找到直径2个端点其中的一个,然后找到离当前点最远的点即为另一个端点。
    1.如果(u)(s-t)的路径上,很明显是对的,到达(u)最远的点必为(s)(t),因为是从(u)开始搜最远的点的。

    2.如果(u)不在(s-t)的路径上,那么从(u)搜最远的点必然与(s-t)相交。

    如图,如果u搜到最远的点为T,那么(dis(u,t) > dis(u,x) + dis(x,t))
    很显然: (dis(s,t ) = dis(s,x) + dis(x,t) < dis(s,T) = dis(s,x) + dis(u,x) + dis(u,T))

    所以 很容易得出必与直径相交,且搜到的点为另一个端点。

    Ⅱ树型DP

    设f[i]表示以i为根,到其子树的叶节点的最大距离。

    考虑如何用子节点更新父节点,
    当前点到叶节点的最大距离=(max){子节点到叶节点的距离+当前点到子节点的距离}。

    设u为当前节点,v为u的子节点,(dis(u,v))是从u−>v这条路径上的距离
    得到转移方程:

    (f[u]=max){(f[v]+dis(u,v))}
    如何维护以u为根的子树中的直径呢
    以u为根子树的直径(=max){u到叶节点的最大距离+子节点到叶节点的最大距离+u到叶节点的距离}
    然后我们钦定一个节点为根,比如1
    得到转移方程:

    (ans=max){(f[u]+f[v]+dis(u,v))}
    ans即为树的直径
    需要注意的是,我们要在更新f[u]之前更新ans,因为从u经过v到叶节点的路径是最长的路径,这样这条路径会被更新两次

    这样做一定会选出u到叶节点最长的两条路径

    void dp(int now)
    {
    	vis[now]=1;
    	for(int i=head[now];i;i=d[i].nxt)
    	{
    		int v=d[i].to;
    		if(vis[v])	continue;
    		dp(v);
    		ans=max(ans,dis[now]+dis[v]+d[i].w);
    		dis[now]=max(dis[now],dis[v]+d[i].w);
    	}
    }
    
  • 相关阅读:
    结构体和指针
    冒泡排序、指针、函数
    指针学习笔记
    C++学习笔记
    背包问题
    零钱兑换2【DP】
    零钱兑换1【DP】
    执行hadoop jar命令时报Not a valid JAR的原因分析和解决方案
    斐波那契数列
    具有n个结点的二叉树有多少种形态
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12546663.html
Copyright © 2011-2022 走看看