Loading [MathJax]/jax/output/CommonHTML/jax.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >树的直径

树的直径

作者头像
hotarugali
发布于 2022-03-03 12:06:04
发布于 2022-03-03 12:06:04
83800
代码可运行
举报
运行总次数:0
代码可运行

1. 简介

树中所有简单路径的最大值即为树的直径,可以通过两次 DFS 或者树形 DP 在 时间内求解。

2. 思路

2.1 两次 DFS

  • 首先将任意一个结点 看作是树根,然后进行 DFS 求出最远的结点;则 一定是树的直径的其中一个端点。

证明   假设结点 之间唯一的简单路径为树的直径, 表示结点之间的唯一的简单路径的长度。若该最远点 不是树的直径的一个端点,则对于当前根结点 来说:

  1. 如果 二者有一个不与 在同一个子树(假设为),则由于

为直径而 不是直径的端点矛盾。

  1. 如果 均与 在同一个子树,易知树的直径没有经过树根。设该子树根为,则易知,于是一定为子树中的最大值,即 为子树 的最远点,对子树 同样进行上述分析,以此类推。

综上可知,一定是树的直径的一个端点。 推论:树中任意结点的最远点要么是,要么是)为树的直径)。   证明同上,略。

  • 然后将 看作是树根,再进行一次 DFS 求出最远点 ,则 之间的简单路径长度即为树的直径。

2.2 树形 DP

  • 定义树的高度为树根到所有结点的简单路径的最大值,次高度为树根到所有结点的简单路径第二大的值()。
  • 对于树中任意一个结点 ,若到其子树中的最远结点的距离为,设所有 中最大的二者为,对应的 的子树为(没有子树 = 子树对应的为零,即没有足够的子树可以看作有 为零的对应子树),则子树中过结点 的最长简单路径等于

子树 的高度等于

其中,取遍 的所有子树,即对应子树的高度和次高度。

  • 由于树的直径一定是以树中某个结点 为根的子树中过结点的最长简单路径,因此计算每个树结点的过结点 的最长简单路径,同时维护一下最大值即可。
  • 计算每个树结点 的过结点 的最长简单路径就是一个树形 dp 问题:以当前结点为根的子树的高度和次高度的解取决于其子树的高度,而需要计算的最长简单路径即为子树的高度和次高度之和。

3. 代码

【注】以下模板均是基于无权树求树的直径,有权树只需在前向星中记录一下边权,然后更新结点高度/深度不是 + 1 而是 + 对应边权即可。

3.1 两次 DFS

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

#ifndef _DIAMETEROFTREE_
#define _DIAMETEROFTREE_
#define ll int 
#define MAXN 10005

// 树的直径
struct DiameterOfTree{ 
    // 前向星存边
    ll cnt;         // 动态开点
    ll head[MAXN];  // 第一条出边
    struct Edge{
        ll to;      // 边的终点
        ll next;    // 下一条边
    }e[MAXN<<1];    // 存取双向边
    // 初始化前向星
    void init() {
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    // 添加双向边
    void addEdge(ll u, ll v) {
        // 存取双向边
        e[cnt].next = head[u];
        e[cnt].to = v;
        head[u] = cnt++;
        e[cnt].next = head[v];
        e[cnt].to = u;
        head[v] = cnt++;
    }
    // DFS 求深度最大的结点
    ll ans;         // 最大深度结点
    ll vis[MAXN];   // 标记数组
    ll depth[MAXN]; // 深度数组
    void dfs(ll u) {
        vis[u] = 1;
        for(ll i = head[u]; i != -1; i = e[i].next) {
            ll v = e[i].to;
            if(!vis[v]) {
                depth[v] = depth[u] + 1;
                if(depth[v] > depth[ans]) {
                    ans = v;
                }
                dfs(v);
            }
        }
    }
    // 求解树的直径
    ll getDiameter(ll u) {
        // 第一遍 DFS
        ans = u;
        memset(vis, 0, sizeof(vis));
        memset(depth, 0, sizeof(depth));
        dfs(u);
        // 第二边 DFS
        memset(vis, 0, sizeof(vis));
        memset(depth, 0, sizeof(depth));
        dfs(ans);
        return depth[ans];
    }
};
#endif

3.2 树形 dp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

#ifndef _DIAMETEROFTREE_
#define _DIAMETEROFTREE_
#define ll int 
#define MAXN 10005

// 树的直径
struct DiameterOfTree{
    // 前向星存边
    ll cnt;         // 动态开点
    ll head[MAXN];  // 第一条出边
    struct Edge{
        ll to;      // 边的终点
        ll next;    // 下一条边
    }e[MAXN<<1];    // 存取双向边
    // 初始化前向星
    void init() {
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    // 添加双向边
    void addEdge(ll u, ll v) {
        // 存取双向边
        e[cnt].next = head[u];
        e[cnt].to = v;
        head[u] = cnt++;
        e[cnt].next = head[v];
        e[cnt].to = u;
        head[v] = cnt++;
    }
    // DFS 树形 dp 
    ll diameter;        // 树的直径
    ll vis[MAXN];       // 标记数组
    ll dfs(ll u) {
        vis[u] = 1;
        ll h1 = 0, h2 = 0;
        for(ll i = head[u]; i != -1; i = e[i].next) {
            ll v = e[i].to;
            if(!vis[v]) {
                ll h = dfs(v) + 1;
                if(h > h1) {
                    h2 = h1;
                    h1 = h;
                } else if(h > h2) {
                    h2 = h;
                }
            }
        }
        diameter = max(diameter, h1+h2);
        return h1;
    }
    // 求解树的直径
    ll getDiameter(ll u) {
        diameter = 0;
        memset(vis, 0, sizeof(vis));
        dfs(u);
        return diameter;
    }
};
#endif
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
使用Python生成一张用于登陆验证的字符图片
Python Pillow库的简单使用 使用Python生成一张用于登陆验证的字符图片, 代码使用了Pillow,Anaconda已经默认安装此库,如果你使用的是官方版的Python需要先下载此库。 代码如下,在注释中予以说明: from PIL import Image, ImageDraw, ImageFont, ImageFilter import random #定义一个生成随机字符的函数 ASII码表 48-57: 0-9 65-90: A-Z 97-122: a-z def randCha
Steve Wang
2018/02/05
8740
使用Python生成一张用于登陆验证的字符图片
Python实战-游戏(四则运算小游戏)
编程世界既神秘又充满乐趣,而今天,我们又将一起踏上学习编程的奇妙旅程,今天我们将用python通过编写简单而有趣的四则运算游戏,探索代码背后的魔法力量。无论你是完全的初学者还是有一定经验的编程爱好者,这个项目都将为你打开编程的大门,让你体验到编程的乐趣与成就感。
一个风轻云淡
2024/03/22
3110
Python简易验证码生成程序
from PIL import Image, ImageDraw, ImageFont import random import string #所有可能的字符,主要是英文字母和数字 characters = string.ascii_letters+string.digits #获取指定长度的字符串 def selectedCharacters(length): '''length:the number of characters to show''' result = "" fo
Python小屋屋主
2018/04/16
7410
python通过pil生成图片验证码
# -- coding: utf-8 -- 导入三个模块 import Image,ImageDraw,ImageFont import random import math '''基本功能''' 图片宽度 width = 100 图片高度 height = 40 背景颜色 bgcolor = (255,255,255) 生成背景图片 image = Image.new('RGB',(width,height),bgcolor) 加载字体 font = ImageFont.truetype('FreeSan
代码伴一生
2021/11/03
6260
利用机器学习识别验证码(从0到1)
利用机器学习识别验证码的思路是:让计算机经过大量数据和相应标签的训练,计算机习得了各种不同标签之间的差别与关系。形成一个庞大的分类器。此时再向这个分类器输入一张图片。分类器将输出这个图片的“标签”。图片识别过程就完毕了。
李玺
2021/11/22
8470
利用机器学习识别验证码(从0到1)
pyocr库
使用预先训练好的模型(例如Tesseract中的LSTM模型),对提取的特征进行模式匹配,以确定每个字符的可能身份。
哲学家阿多诺
2024/09/01
2200
pyocr库
Django之随机图形验证码
一个input输入框和一个用div包裹的img标签,用Bootstrap的栅格系统各占6格(只是为了美观,可以不用样式)
py3study
2020/01/17
1.1K0
四则运算作业
代码: # -*- coding: utf-8 -*- import random from fractions import Fraction from envs.py3k.Lib.symbol import except_clause print ("小学四则运算测试:(结果保留1位有效数字)") ops = ['+', '-', '*', '/'] # 锟斤拷锟斤拷锟� ans = "" # 锟矫伙拷锟截达拷 num = 1 # 锟斤拷锟� rightnum = 0 t = 0 while
py3study
2020/01/17
5030
python实现生成验证码的逻辑
 假设我们有一个fonts的文件夹,里面有1.ttf,2.ttf,3.ttf三个字体文件 具体代码实现代码codes.py: # coding:utf8 from PIL import ImageDraw, ImageColor, ImageFile, ImageFont, ImageFilter, Image import random import os import uuid class Codes: # 定义随机字符 def random_chr(self):         num = 
禹都一只猫olei
2018/05/25
5510
利用Python几行代码批量生成验证码
附件:代码地址 https://github.com/Testworm/app_ui/blob/master/authCode.py 
互联网金融打杂
2019/12/11
6920
利用Python几行代码批量生成验证码
Python3实现验证码
Python3 实现创建验证码图片 一:准备工作,需要安装PIL,安装方式,pip install Pillow 二:具体实现 #!/usr/bin/env python3 # coding:UTF-8 """" 文件说明: """ from PIL import Image, ImageDraw, ImageFont import random import string import os def get_code(width=100, height=40, fontSize=35):
py3study
2020/01/10
3710
python3 pillow生成简单验
使用Python的pillow模块 random 模块随机生成验证码图片,并应用到Django项目中
py3study
2020/01/02
4340
[置顶] 用python生成验证码图片
基本上大家使用每一种网络服务都会遇到验证码,一般是网站为了防止恶意注册、发帖而设置的验证手段。其生成原理是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR)。下面就详细讲解如何生成验证码。
代码伴一生
2021/11/02
1.7K0
为什么每次登录系统都有烦人的验证码?
每次登录系统的时候总是要输入烦人的验证码,那么我们今天就思考这个问题,为什么要有验证码这个功能?很多伙伴应该都知道:
不安分的猿人
2020/06/15
1.2K0
使用Python生成基础验证码教程
pillow是Python平台事实上的图像处理标准库。PIL功能非常强大,但API却非常简单易用。 所以我们使用它在环境里做图像的处理。
步履不停凡
2019/09/11
6520
纯代码系列:Python实现验证码图片(PIL库经典用法用法,爬虫12306思路)
现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一。这里就不详细介绍了,相信大家都遇到过。
用户2966292
2020/10/23
8240
Django实战-信息资讯-图形验证码
Django网络应用开发的5项基础核心技术包括模型(Model)的设计,URL 的设计与配置,View(视图)的编写,Template(模板)的设计和Form(表单)的使用。
小团子
2019/07/18
6210
Django实战-信息资讯-图形验证码
Day21第三方模块Pillow&requests
Pillow PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了。PIL功能非常强大,但API却非常简单易用。 由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。 模糊效果: from PIL import Image, ImageFilter # 打开一个jpg图像文件,注意是当前路径: im
林清猫耳
2018/04/26
8140
随机验证码
Python生成随机验证码,需要使用PIL模块.python3则是pillow 安装: ? 1 pip3 install pillow 基本使用 1. 创建图片 ? 1 2 3 4 5 6 7 8
用户1214487
2018/01/24
1.8K0
Pillow模块图片生成
0825自我总结 Pillow模块图片生成 一.模块安装 pip3 install pillow 二.模块的载入 import PIL 三.django结合img标签生成图片 img.html <img src='/img/'> url.py from django.conf.urls import url from django.contrib import admin #主路由导入视图内函数 from app import views urlpatterns = [ url(r'^img/',
小小咸鱼YwY
2019/09/11
1.3K0
相关推荐
使用Python生成一张用于登陆验证的字符图片
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验