C C++ 题解LeetCode2360图中的最长环示例

让我们详细讲解一下“C C++ 题解LeetCode2360图中的最长环示例”的完整攻略。

题目描述

题目传送门:LeetCode2360图中的最长环

题目描述:

给你一棵有n个节点的有根树,节点从0~n-1编号,树的根节点为0.

叶节点是指没有直接连接任何下一级节点的节点。本题中,树的节点从1到n编号, 而非从0到n-1编号.

节点 i 的父亲是 father[i]。一个节点的直接子节点是该节点连接的所有节点中编号最小的那些。例如,在图中的树中,节点 1 连接着节点 2 和节点 3 且节点 2 是节点 1 的子节点,节点 3 是节点 1 的另一个直接子节点。该树经过修改变成了一棵普通的无根树。你需要重新连接树边,以得到一棵直径最大的树。直径是树上最长路径的长度。用所需修改的边的个数来返回该长度。

题目分析

在题目中,我们需要把一个有根树转化为无根树,然后求出该无根树的直径,再根据需要修改的边数返回最长的直径长度。

先看怎样将一个有根树转化为无根树。我们可以让树中的任意一个节点作为根节点,以其他节点为根节点建立子树。但是,本题中我们并不知道那个节点才是原来的根节点。因此,我们需要枚举所有的节点作为根节点,以该节点为根节点建立子树并求出该子树的最长直径。最终所有的直径长度中的最大值即为所求。

无根树的直径可以用两次dfs求出,详细的求解过程可以参见我的博客:无根树的直径

接下来,我们再看怎样计算其中添加的边数。

我们发现,在有根树中,父节点到子节点的边是确定的。因此,每当我们枚举一个节点作为根节点并对树进行转化时,会造成一部分父节点到子节点的边的改变,不同姿势转换成的无根树造成的改变不同,我们需要对这些结果进行分析。

我们采用dfs从一个虚拟的根节点 root 开始遍历整个无根树,记录每个节点到虚拟根节点的距离,并维护一条最长路径,路径上的两个节点即为无根树的直径的两个端点。如果某个节点的两个子节点的距离和大于现有的最长路径长度,则更新最长路径。记录这个最长路径长度 later。

要想得出我们需要添加的边数 diff,先计算出无根树之前的最长直径长度 former。

diff = later - former。

最后,我们就可以得到这道题的完整解法了。

一条示例说明

以示例图为例,具体思路如下:

  1. 先将节点0作为根节点, 枚举所有节点, 以该节点为根建立无根树, 并计算该无根树的直径, 该部分的添加的边数为3.
  2. 然后将节点1作为根节点, 输入的树在以节点1为根的树形结构中的样子为:
   1(1)
  /     \
2(2)    3(4)

计算该树的时候需要修改2到4的路径,因此 diff = 1。最长直径为2。因此我们最重终态的答案应该为5 + 2 = 7

  1. 最后再枚举2和3各一次即可。

不难发现,我们需要维护两个比较重要的变量:later 和 former。 下一个示例同理。

另一条示例说明

现在看练习题目传送门:第 113 周周赛 第二题

给出的树形结构为:

   3(1)
  /     \
2(2)    0(3)
   \     
    1(4)

初始无根树:

   3(1)
  /     \
2(2)    0(3)
   \     
    1(4)

以 3 作为根:

   3(1)
  /     \
2(2)    0(3)
   \     
    1(4)

该部分的添加边数为1,最长路径为1。

以 2 作为根:

       2(1)
      /   \
    3(2)  1(4)
      \     
       0(3)

该部分的添加边数为1,最长路径为3。

以 0 作为根:

   0(1)
  /     \
3(2)    2(3)
   \     
    1(4)

该部分的添加边数为1,最长路径为3。

以上两例都说明了这个题的思路,对于这些奇怪的示例可以用调试模式查看获得更好的体验。

代码实现

参考代码如下:

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C C++ 题解LeetCode2360图中的最长环示例 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 一文详解Qt如何读取和写入配置文件的数据

    一文详解Qt如何读取和写入配置文件的数据 概述 在Qt程序开发过程中,有时候需要读取和写入一些配置文件数据,例如程序的设置、用户个性化的设置等,本文将详细讲解Qt如何读取和写入配置文件的数据。 读取配置文件数据 Qt提供了QSettings类,可以用于读取和写入配置文件数据,以下是使用QSettings读取配置文件数据的示例代码: QSettings set…

    C 2023年5月24日
    00
  • C++调用C函数实例详解

    C++调用C函数实例详解 C++调用C函数是一种常见的操作,有很多场合需要这种操作。下面详细讲解C++调用C函数的完整攻略。 1. 头文件引入 要在C++中调用C函数,首先要引入对应的C函数的头文件。例如,要调用标准库中的函数,需要在C++源文件中使用如下代码: extern "C" { #include <stdio.h> …

    C 2023年5月23日
    00
  • C语言的动态内存管理你了解吗

    C语言的动态内存管理是非常重要的知识点,掌握了动态内存管理,可以更好地理解程序的运行过程。下面是动态内存管理的完整攻略: 1. 动态内存分配的概念 动态内存分配是在程序运行时向操作系统申请内存空间,对内存进行分配、释放和管理的过程。与静态内存分配不同,静态内存分配在程序编译时就已经确定了。动态内存分配通常用于需要运行时才完成大小和数量的确定的情况下,例如输入…

    C 2023年5月23日
    00
  • C语言 字符串指针详解及示例代码

    C语言 字符串指针详解及示例代码 什么是字符串指针? 在C语言中,字符串指针通常用来存储字符串的地址,字符串指针变量以及字符串变量有所不同:字符串变量是进行字符串内容及长度操作的,而字符串指针变量不同,它仅存储字符串的地址,这意味着字符串指针变量可以指向不同的字符串。 字符串指针变量的声明方式: char *stringPointer; 字符串指针的赋值 字…

    C 2023年5月24日
    00
  • C语言指针基础知识实例讲解

    下面我就来详细讲解一下“C语言指针基础知识实例讲解”的完整攻略。 知识点概述 首先,我们需要了解一下指针是什么。指针是一个变量,其值为另一个变量的地址。换句话说,指针是一种存储另一个变量地址的变量。在C语言中,指针的数据类型在其前面加上*号。 我们还需要知道如何声明和初始化指针。指针的声明与其他变量类似,只需在变量名前面加上*号。例如,int *p表示p是一…

    C 2023年5月23日
    00
  • C++ 搬水果贪心算法实现代码

    C++搬水果贪心算法实现代码的攻略如下: 什么是贪心算法? 贪心算法(Greedy Algorithm)又称贪心策略,是指在利用当前信息的情况下,做出当下最优的选择。贪心算法不会考虑到全局的最优解,而只关注当下的最优解。贪心算法在求解最优解的过程中,通常需要证明其正确性,并且使用贪心算法求得的解不一定是全局最优解,但是可以得到比较优秀的近似解。 搬水果问题的…

    C 2023年5月22日
    00
  • VS Code C/C++环境配置教程(无法打开源文件“xxxxxx.h”或者检测到 #include 错误,请更新includePath)(POSIX API)

    下面我将基于该主题为您详细讲解 C/C++ 环境配置教程。 问题描述 在使用 VS Code 编辑 C/C++ 项目时,有时会遇到“无法打开源文件”或“检测到 #include 错误”的问题,这是由于编译器找不到相关的头文件或库文件所致。 解决方案 1. 安装 C/C++ 扩展 首先,需要在 VS Code 中安装 C/C++ 扩展,该扩展可以提供代码补全、…

    C 2023年5月30日
    00
  • C语言将24小时制转换为12小时制的方法

    下面是“C语言将24小时制转换为12小时制的方法”的完整攻略。 核心思路 我们可以通过判断输入的小时数是上午还是下午,然后将其转换为12小时制,并输出结果。具体的思路如下: 读取用户输入的24小时制时间,并将其保存为一个整数,此处用变量hour表示。 如果用户输入的小时数在12小时之前,那么它就是上午时间,输出相应的12小时制时间和“AM”;如果用户输入的小…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部