python coding with ChatGPT 专题1 | 树的直径

文章目录

  • 定义
  • 题目
    • 特点
  • 树的表示
    • 字典存储邻接表
    • TreeNode类
  • 深度优先 (两次DFS法)
  • 动态规划 (树形DP)
    • 优势
  • 相似题目
  • 参考资料

定义

树上任意两节点之间最长的简单路径即为树的「直径」。

题目

给定一棵树,求出这棵树的直径,即树上最远两点的距离。
包含n个结点,n-1条边的连通图称为树。
示例1的树如下图所示。其中4到5之间的路径最长,是树的直径,距离为5+2+4=11

在这里插入图片描述

输入:

python">edge_list = [[0,1],[1,5],[1,2],[2,3],[2,4]]
edge_value = [3,4,2,1,5]
n = 6

特点

一个没有固定根结点的树称为 无根树(unrooted tree)。无根树有几种等价的形式化定义:

  • 有 [n] 个结点, [n-1] 条边的连通无向图

  • 无向无环的连通图

  • 任意两个结点之间有且仅有一条简单路径的无向图

  • 任何边均为桥的连通图

  • 没有圈,且在任意不同两点间添加一条边之后所得图含唯一的一个圈的图

树的表示

字典存储邻接表

python">def get_tree(edge_list, edge_value, n):
    tree = {}
    for i in range(n):
        tree[i] = []
    for x, y in zip(edge_list, edge_value):
        tree[x[0]].append((x[1], y))
        tree[x[1]].append((x[0], y))
    return tree

TreeNode类

python">class TreeNode:
	def __init__(val):
		self.val = val
		self.neighbors = []
	
	def add_neighbor(self, node, weight):
		self.neighbors.append((node, weight))
python">def build_tree(edge_list, edge_value, n):
	nodes = [TreeNode(i) for i in range(n)]
	for (start, end), weight in zip(edge_list, edge_value):
		nodes[start].add_neighbor(end, y)
		nodes[end].add_neighbor(start, y)
	return nodes[0]

深度优先 (两次DFS法)

解决这个问题的一个有效方法是利用深度优先搜索(DFS)。这个方法可以分为两步来完成:

  • 从任意一个结点出发,执行一次深度优先搜索(DFS),找到距离它最远的结点。
  • 以步骤1中找到的结点作为起点,再次执行深度优先搜索(DFS),找到距离它最远的结点的距离,这个距离即为树的直径。

为什么这个方法有效?第一次DFS帮助我们定位到树的一端,然后第二次DFS从这一端出发能够找到最远的另一端,这就保证了我们计算出的距离是最长的路径。

在这里插入图片描述

dfs逻辑:

python"># simple dfs for dict
def simple_dfs(current_node, parent, tree)
	print(current_node)
	for node, _ in tree[current_node):
		if node != parent:
			simple_dfs(node)

# simple dfs for treenode
def simple_dfs(current_node, parent)
	print(current_node)
	for node _ in current_node.neighbors:
		if node != parent:
			simple_dfs(node)	

解题代码:

方法一:字典形式

python"># dict
def get_tree(edge_list, edge_value, n):
    tree = {}
    for i in range(n):
        tree[i] = []
    for x, y in zip(edge_list, edge_value):
        tree[x[0]].append((x[1], y))
        tree[x[1]].append((x[0], y))
    return tree
    
def dfs(current_node, parent, tree, distance):
	farthest_node = current_node
	max_distance = distance
	for node, weight in tree[current_node]:
		if node != parent:
			this_farthest_node, this_max_distance = dfs(node, current_node, tree, distance+weight)
			if this_max_distance > max_distance:
				max_distance = this_max_distance
				farthest_node = this_farthest_node
	return farthest_node, max_distance

def treeDiameter(edge_list, edge_value, n):
	tree = get_tree(edge_list, edge_value, n)
	farthest_node, _ = dfs(0, None, tree, 0)
	_, max_distance = dfs(farthest_node, None, tree, 0)
	return max_distance

方法二:TreeNode形式

python">class TreeNode:
    def __init__(self, val):
        self.val = val
        self.neighbors = []

    def add_neighbor(self, node, weight):
        self.neighbors.append((node, weight))


def build_tree(edge_list, edge_value, n):
    nodes = [TreeNode(i) for i in range(n)]
    for (start, end), weight in zip(edge_list, edge_value):
        nodes[start].add_neighbor(nodes[end], weight)
        nodes[end].add_neighbor(nodes[start], weight)
    return nodes[0]

def dfs(current_node, parent, distance):
    farthest_node = current_node
    max_distance = distance
    for node,weight in current_node.neighbors:
        if node != parent:
            this_farthest_node, this_max_distance = dfs(node, current_node, distance+weight)
            if this_max_distance > max_distance:
                farthest_node = this_farthest_node
                max_distance = this_max_distance
    return farthest_node, max_distance

def treeDiameter(edge_list, edge_value, n):
    current_node = build_tree(edge_list, edge_value, n)
    farthest_node, _ = dfs(current_node, None, 0)
    _, max_distance = dfs(farthest_node, None, 0)
    return max_distance

动态规划 (树形DP)

定义一个DP状态来表示从当前节点出发能够达到的最长路径长度
这个方法的关键在于,我们在遍历树的过程中,考虑通过这个节点的最长路径(也就是这个节点作为路径中间点,连接两个最长的子路径)。
在这里插入图片描述

python">def calculate_diameter(node, parent, diameter):
    max_depth1, max_depth2 = 0, 0  # 存储当前节点的最大和次大深度

    for neighbor, weight in node.neighbors:
        if neighbor == parent:
            continue

        # 获取到该邻接节点的最大深度
        depth = calculate_diameter(neighbor, node, diameter) + weight

        # 更新最大和次大深度
        if depth > max_depth1:
            max_depth2, max_depth1 = max_depth1, depth
        elif depth > max_depth2:
            max_depth2 = depth

    # 更新通过当前节点的最大直径
    diameter[0] = max(diameter[0], max_depth1 + max_depth2)

    # 返回到当前节点的最大深度
    return max_depth1

def treeDiameter(edge_list, edge_value, n):
    root = build_tree(edge_list, edge_value, n)
    diameter = [0]  # 使用列表作为引用传递,以便在递归中更新
    calculate_diameter(root, None, diameter)
    return diameter[0]

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

优势

通过树形DP,我们能够在一次遍历中完成这个计算,无需执行两次DFS。这种方法尤其在处理大型树结构时显示出其效率和优势。

相似题目

1245. 树的直径

参考资料

https://oi-wiki.org/graph/tree-diameter/


http://www.niftyadmin.cn/n/5458619.html

相关文章

SQLServer sys.default_constraints介绍

sys.default_constraints 是 SQL Server 的系统视图,它包含了数据库中所有默认约束的信息。默认约束是数据库对象(如表中的列)的约束,它为列定义了一个默认值,当在插入新行时没有为该列提供值时,将使用这个…

Java 之 IO 流-文件的加密、断点续传、切割、递归拷贝、序列化克隆 等代码实现

IO-文件的加密、断点续传、切割、递归拷贝等 IO流,这章内容大家都感觉内容多,杂,难。下面有几个作业题,你会几个? 1.大文件分割及还原合并 描述:有一个很大的文件需要拷贝,但是U盘只有1G,该怎么办?比如现有一个4G大的文件,需要分割成多个500M的文件,存在指定的文件…

ZYNQ学习之Ubuntu下Linux文件系统与用户权限

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Linux 文件系统 1.1 Linux 文件系统简介以及类型 操作系统的基本功能之一就是文件管…

Web框架开发-Django-分页器

一、Django的分页器(paginator) view 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 from django.sh…

VESTA模拟计算XRD标准卡片

先上Crystallography Open Database网站下载标准CIF卡片&#xff08;以PbI2为例&#xff09; 1.直接进网站搜元素就行 2.点CIF直接下载 3.打开VESTA&#xff0c;导入刚刚下载的CIF 4.导入成功就是这样的 5.按照我这个操作来计算 6.点Calculation 7.已经计算出来了&#xff…

Transformers —— 以通俗易懂的方式解释-Part 1

公众号:Halo咯咯,欢迎关注~ 本系列主要介绍了为ChatGPT以及许多其他大型语言模型(LLM)提供支持的Transformer神经网络。我们将从基础的Transformer概念开始介绍,尽量避免使用数学和技术细节,使得更多人能够理解这一强大的技术。 Transformers —— 以通俗易懂的方式解释…

EXCEL通过VBA字典快速分类求和

EXCEL通过VBA字典快速分类求和 汇总截图 Option ExplicitOption Explicit Sub answer3() Dim wb As Workbook Dim sht As Worksheet Set wb ThisWorkbook Set sht wb.Worksheets(2) Dim ss1 As Integer Dim ss2 As Integer Dim i As Integer Dim j As Integer j 1Dim aa()…

基于机器视觉的智能物流机器人的设计与开发

标题&#xff1a;基于机器视觉的智能物流机器人的设计与开发 摘要&#xff1a; 随着电子商务和物流行业的快速发展&#xff0c;智能物流机器人作为一种高效、准确的自动化解决方案&#xff0c;正逐渐受到广泛关注。本文围绕基于机器视觉技术的智能物流机器人的设计与研发展开&…