AcWing 1072. 树的最长路径(DFS与树形DP)

news2024/11/9 10:09:52

AcWing 1072. 树的最长路径(树形DP)

  • 一、题目:
  • 二、思路:
  • 三、代码:
  • 四、树形DP
    • 1、状态表示
    • 2、状态转移
    • 3、循环设计
    • 4、初末状态
    • 5、代码实现

一、题目:

在这里插入图片描述

二、思路:

为了方便,我们利用下面这个图做讲解:
在这里插入图片描述
这颗树的最长路径必定经过的是图中的点,因此,**我们可以去枚举经过图中每个点的最长路径,然后再这些路径中选出一个最长的作为答案。**那么我们需要怎么做呢?

我们这里采用的是DFS(深度优先搜索),如果对DFS不了解的话,作者建议去看一下之前对DFS算法的专门讲解:第十三章 DFS与BFS(保姆级教学!!超级详细的图示!!) 和 第十四章 图的存储及图的DFS(超级详细!!逐行解析!!)

很多同学不会写DFS,其实根本原因在于每道题中DFS递归函数的含义都是不一样的,而想要写出DFS就要明白DFS在每道题语境中的含义。

在本道题中,我们将DFS写成下面的样子:

int dfs(int u,int father)

**这个函数的作用是返回到u点最远的点的距离。**那么这么定义的作用是什么呢?

我们看下面的图:

在这里插入图片描述
由于我们求的是最大距离,而最大距离必须要比较以后才能知道,因此就需要求出到u点的所有距离。然后我们选出前两个最大的。这样这两个距离和u点就构成了一个经过u点的最大路径。(详细过程如图中所示)

也就是说我们在求到u点的最大距离的过程中顺便求出了经过该点的最长路径。

并且,我们的DFS会去遍历每个点,所以经过每个点的最长路径都会求出来,此时我们只需要定义一个全局变量记录所有最长路径中最长的一个即可。

这里还有几个细节处理,前两个最大的距离组成了我们经过u点的最大距离,但是如果最大的距离中是负的,那么我们就不加上这个距离,因为加上的话只会减少。

另外,由于题目中是无向边,所以在遍历u的子节点的时候,也会遍历到u的父节点,所以我们参数中多写一个父节点,这样做的目的就是防止循环遍历造成死循环。

三、代码:

#include<bits/stdc++.h>
using namespace std;
typedef  pair<int,int> pii;
const int N=1e4+10;
vector<pii>g[N];
int n;
int ans;
int dfs(int u,int father)
{
    int d1=0,d2=0;
    for(int i=0;i<g[u].size();i++)
    {
        auto j=g[u][i];
        if(j.first==father)continue;
        int d=dfs(j.first,u)+j.second;
        if(d>=d1)
            d2=d1,d1=d;
        else if(d>d2)
            d2=d;
    }
    ans=max(ans,d1+d2);
    return d1;
}
int main()
{
    cin>>n;
    for(int i=0;i<n-1;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a].push_back({b,c});
        g[b].push_back({a,c});
    }
    dfs(1,-1);
    cout<<ans<<endl;
    return 0;
}

四、树形DP

通过上面的代码我们发现,我们的时间复杂度是 O ( n ) O(n) O(n)的,因为我们的DFS函数遍历了树中的每一个点,而我们的主函数中只调用了一次DFS,所以总共的时间复杂度是 O ( n ) O(n) O(n)

这个时间复杂度很低,打破了我们对DFS的认识,按照以前对DFS的理解,提到DFS我们就会想到两个字:暴力。并且我们对DFS的时间复杂度也有着刻板地印象:指数级别。

这道题之所以时间复杂度低,就是因为这道题虽然代码上看起来是深搜,实际上是DP的思想。

那么什么是DP的思想呢?

DP的思想就是:利用子问题解决当前问题,从小规模的问题开始解决,利用小规模的问题的解解决大规模的问题。

那么我们利用DP的分析过程去解释刚刚的DFS思路:

1、状态表示

f [ 1 / 2 ] [ u ] f[1 / 2][u] f[1/2][u],其中 f [ 1 ] [ u ] f[1][u] f[1][u]表示树中的其他点到达该点的最大距离 f [ 2 ] [ u ] f[2][u] f[2][u]表示树中的其他点到达该点的次大的距离

2、状态转移

在这里插入图片描述
我们发现 f [ 1 ] [ u ] f[1][u] f[1][u]可以利用b,x,c三个点转移过来,那么写成然后在三种情况中取一个最大值。可以写成:

f [ 1 ] [ u ] = m a x ( f [ 1 ] [ b ] + w [ b ] , f [ 1 ] [ x ] + w [ x ] , f [ 1 ] [ c ] + w [ c ] ) f[1][u] = max\big(f[1][b]+w[b],f[1][x]+w[x],f[1][c]+w[c]\big) f[1][u]=max(f[1][b]+w[b],f[1][x]+w[x],f[1][c]+w[c])
那么 f [ 2 ] [ u ] f[2][u] f[2][u]的转移也是类似的,只不过是从三个里面挑出一个次大的。

3、循环设计

循环的话,我们发现这道题由于是一个树形的图,所以很难写成我们 f o r for for循环的样子。因此,我们这里只能用DFS来表示这里的循环。

于是我们就发现了树形DP中其实分析的思路和别的DP问题是一致的,只不过是循环的方式从for循环改成了DFS。

4、初末状态

初始化的话,就全部初始化为0就好了,有人说为什么不弄成负数,其实很简单,如果有一条路线是负的,那我不选它就好了。因此我们能始终保证最优解大于等于0。

末尾状态的话,其实也好表示,这道题求的是最长直径,我们只需要将 f [ 1 ] [ u ] f[1][u] f[1][u] f [ 2 ] [ u ] f[2][u] f[2][u]加在一起即可。

然后在所有的 f [ 1 ] [ i ] f[1][i] f[1][i]中求出一个最大值。
在这里插入图片描述

5、代码实现

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10, M = 2 * N;
int h[N], e[M], ne[M], w[M], idx;
int f[3][N];

void add(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c;
    h[a] = idx++;
}

void dfs(int u, int father)
{
    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if(j == father)continue;
        dfs(j, u);
        if(f[1][j] + w[i] >= f[1][u])
        {
            f[2][u] = f[1][u];
            f[1][u] = f[1][j] + w[i];
        }
        else if(f[1][j] + w[i] >= f[2][u])
            f[2][u] = f[1][j] + w[i];
    }
}

int main()
{
    memset(h, -1, sizeof h);
    int n;
    cin>>n;
    for(int i = 0; i< n - 1; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c),add(b, a, c);
    }
    int res = 0;
    dfs(1,-1);
    for(int i = 1; i <= n; i ++ )
    {
        res = max(f[1][i]+f[2][i], res);
    }
    cout<<res<<endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185321.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3现状—必然趋势?

文章目录&#x1f31f; 专栏介绍&#x1f31f; Vue默认版本&#x1f31f; 拥抱Vue3的UI&#x1f31f; Vue3显著优势&#x1f31f; 专栏介绍 凉哥作为 Vue 的忠诚粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 Vue3 的相关技术文章&#xff0c;Vue 框架目前的地位大…

Python爬虫之Scrapy框架系列(8)——XXTop250电影所有信息同时存储到MySql数据库

现在又不满足于只保存在本地txt文本了&#xff0c;所以来试试存储到数据库mysql里怎么搞呢&#xff1f;&#xff08;首先&#xff0c;要准备好mysql数据库以及navicat数据库可视化管理工具&#xff09; 目录&#xff1a;分析&#xff1a;如何同时存储到本地txt文本以及mysql数据…

回溯详解 LeetCode 46. 全排列 51. N 皇后 52. N皇后 II

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 46. 全排列 51. N 皇后 52. N皇后 II&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 46. 全…

Word处理控件Aspose.Words功能演示:如何在 C# 和Java中将 DOC 转换为 JSON

Aspose.Words 是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。此外&#xff0c; Aspose API支持流行文件格式处…

kvm磁盘管理

kvm磁盘管理虚拟磁盘类型rawqcow2qemu-img常用参数主要参数&#xff1a;查看磁盘信息--info创建磁盘文件--create磁盘容量调整--resize磁盘增加容量磁盘缩小容量(生产环境下禁止操作)磁盘调整容量到指定大小转换磁盘格式--convert检查磁盘镜像在线热添加磁盘附加磁盘到vm实例--…

UI自动化测试面试题总结

文章目录一、请描述实现用户登陆模拟自动化测试的思路。二、基于Web端呈现的产品如何做自动化测试&#xff0c;谈谈你的思路和方向。三、什么是web自动化测试&#xff1f;四、什么是selenium&#xff1f;五、写出selenium中你最熟悉的接口或类(*)六、findElement()和findElemen…

java总结(数组)

1.数组概述数组&#xff08;Array&#xff09;是多个相同数据类型按照一定顺序排列的集合&#xff0c;并使用一个名字命名&#xff0c;通过编号的方式对这些数据进行统一的管理。数组相关概念数组名&#xff1a;下标&#xff08;索引&#xff09;元素数组长度数组特点有序排列数…

sqlserver将mdf文件拆分成多个ndf文件

sqlserver版本&#xff1a;2008R2 1、为什么要拆分 数据库在运行一段时间后mdf文件会迅速增大&#xff0c;这会导致查询速度变慢。或者mdf文件的大小达到了操作系统允许的最大大小&#xff0c;这个时间就必须要进行拆分了。 2、拆分的好处 在没有拆分的时候只有一个mdf主数…

KVM虚拟化技术学习笔记10

虚拟机镜像管理 学习目标&#xff1a; 能够了解KVM虚拟机支持的镜像格式 能够使用qemu-img实现镜像创建 能够使用qemu-img实现镜像查看 能够使用qemu-img实现镜像格式转换 能够了解后备镜像的作用 能够了解差量镜像的作用 能够基于后备镜像制作差量镜像 能够使用差量镜…

SAP ADM100-2.3 系统启动:AS ABAP和AS ABAP+JAVA

一、打开并停止一个SAP Netweaver AS ABAP+JAVA 使用例如SAP MC(SAP Management Console)工具开启并关闭实例。在一个双栈实例中(ABAP+JAVA),JAVA是通过ABAP dispatcher使用Startup and Control Framework开启的,然后它再开启JAVA dispatcher和SP(server Processes)。 …

Qt OpenGL(三十)——Qt OpenGL 核心模式-纹理二(给正方体贴上图片)

提示:本系列文章的索引目录在下面文章的链接里(点击下面可以跳转查看): Qt OpenGL 核心模式版本文章目录 Qt OpenGL(三十)——Qt OpenGL 核心模式-纹理二(给正方体贴上图片) 通过前两篇文章,我们知道了如何绘制一个正六面体和使用纹理贴图,本篇继续介绍在正方体(正…

面试中如何才能有底气的回答,软件测试题库你有必要一用

面试&#xff0c;是决定求职者是否能进入到自己心仪岗位的敲门砖&#xff0c;而对于很多第一次参加软件测试面试的求职来说&#xff0c;想要通过面试就得经过hr的初面以及技术官技术面&#xff0c;前者还好说&#xff0c;可以根据情况临场发挥&#xff0c;而后者&#xff0c;就…

Linux 之十七 Ubuntu 22.04 配置内核版本、GRUB 引导、远程桌面

前段时间重新安装了 Ubuntu 22.04 LTS&#xff0c;安装后没有显示 GRUB 引导页面&#xff08;默认自动跳过&#xff09;&#xff0c;直接使用默认内核启动&#xff0c;而我需要变更一下默认的内核版本&#xff0c;特此记录一下修改过程。 安装其他版本内核 Ubuntu 中安装其他版…

MAC m1 安装 allure

一、下载安装包&#xff0c;并进行解压 1.1 下载安装包 官网下载包地址 1.2 双击 进行 解压 二、配置环境变量 2.1 打开配置文件 在终端输入以下命令 vi ~/.bash_profile【注意】 该命令地址 注意 中间不要出现多余的空格&#xff0c;否则打开会有问题&#xff0c;这个…

学生护眼台灯怎么选?推荐教育部认可护眼灯品牌

现在许多家庭都会购买学生护眼台灯给孩子用&#xff0c;那么学生护眼台灯怎么选&#xff1f;1. 光线的舒适度&#xff0c;才是最关键的&#xff1a;一般会在护眼技术上体现出&#xff0c;有全光谱灯珠、色温舒适、显色指数高、无蓝光危害、无可视频闪等&#xff0c;让光线照射眼…

高效、优雅的对象copy之MapStruct入门到精通,实战踩坑版

一、前言 大家在开发中&#xff0c;最让人头疼的就是&#xff1a;对象之间的拷贝&#xff0c;前端的VO和数据库的Entity不一致&#xff01; 性能最好的就是手动set&#xff0c;主要是枯燥且无技术含量&#xff0c;不仅耗费大量时间而且很容易出错&#xff1b; 所以我们要成为…

jsp 新房销售竞买管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 新房销售竞买管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统采用web模式开发&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

OJ万题详解––赦免战俘(C++详解)

题目 题目背景 借助反作弊系统&#xff0c;一些在月赛有抄袭作弊行为的选手被抓出来了&#xff01; 题目描述 现有 名作弊者站成一个正方形方阵等候 kkksc03 的发落。kkksc03 决定赦免一些作弊者。他将正方形矩阵均分为 4 个更小的正方形矩阵&#xff0c;每个更小的矩阵的边长…

VSCode调试Python文件并指定虚拟环境 附调试说明

记录在使用VSCode调试py文件时遇到的一些问题&#xff1a;1.启用Debug模式进行调试2.调试带参数的python文件3. 调试时指定服务器虚拟环境4. 相对路径出错5 continue&#xff08;继续&#xff09;、step over&#xff08;单步跳过&#xff09;、step in&#xff08;单步调试&am…

【Python学习笔记】2. Python3 环境搭建

前言 将向大家介绍如何在本地搭建 Python3 开发环境。 Python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Python3 环境搭建 本节我们将向大家介绍如何在本地搭建 Python3 开发环境。 Python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Unix (Solaris, Li…