AcWing 1073:树的中心 ← 树形DP

news2024/9/23 15:20:08

【题目来源】
https://www.acwing.com/problem/content/1075/

【题目描述】
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点
到树中其他结点的最远距离最近

【输入格式】
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。

【输出格式】
输出一个整数,表示所求点到树中其他结点的最远距离。

【数据范围】
1≤n≤10000,
1≤ai,bi≤n,
1≤ci≤10^5

【输入样例】

2 1 1 
3 2 1 
4 3 1 
5 1 1

【输出样例】
2

【算法分析】
● 树形 DP
(1)树形 DP 是建立在树上的 DP。
(2)树形 DP 常用的数组
d1[u]:从当前结点 u
向下走的最长路径长度
d2[u]:从当前结点 u
向下走的次长路径长度
up[u]:从当前结点 u 向上走的最长路径长度
p1[u]:从当前结点 u
向下走的最长路径是从哪个结点开始的
p2[u]:从当前结点 u
向下走的次长路径是从哪个结点开始的
(3)树是一种特殊的图,具有
无环的特点,这使得树形 DP 在很多问题上比普通 DP 更为直观高效。在树形 DP 问题中,通常需要处理与结点相关的状态,并利用树的层次结构,“向下走”或“向上走”递归地解决问题。“向下走”很容易,直接 DFS 即可。怎么“向上走”呢?其实,在本题中,“向上走”就是求某个结点 j 的父结点 u 不经过该结点 j 的最长路径长度。一般地,一个结点 j 的向上最长路径长度,就是它的父结点 u 的向上最长路径长度与向下最长路径长度的最大值。但是,如果父结点 u 的向下最长路径经过了结点 j,那么结点 j 的向上最长路径长度,就是它的父结点 u 的向上最长路径长度与向下次长路径长度的最大值。示意图如下所示:

代码如下所示:

if(p1[u]==j) up[j]=max(up[u],d2[u])+val[i];
else up[j]=max(up[u],d1[u])+val[i];

​​​​其中,上面代码可由如下示意图直观展现。

● 链式前向星:https://blog.csdn.net/hnjzsyjyj/article/details/139369904
val[idx]:存储编号为 idx 的边的
e[idx]:存储编号为 idx 的结点的
ne[idx]:存储编号为 idx 的结点指向的结点的编号
h[a]:存储头结点 a 指向的结点的编号

(1)加边操作
无权图的链式前向星的加边操作核心代码如下:

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

有权图的链式前向星的加边操作核心代码如下: 

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

(2)基于链式前向星的深度优先搜索(DFS)的核心代码

void dfs(int u) {
    cout<<u<<" ";
    st[u]=true;
    for(int i=h[u]; ~i; i=ne[i]) { //~i; equivalent to i!=-1;
        int j=e[i];
        if(!st[j]) {
            dfs(j);
        }
    }
}

(3)基于链式前向星的广度优先搜索(BFS)的核心代码

void bfs(int u) {
    queue<int>q;
    st[u]=true;
    q.push(u);
    while(!q.empty()) {
        int t=q.front();
        q.pop();
        cout<<t<<" ";
        for(int i=h[t]; ~i; i=ne[i]) { //~i; equivalent to i!=-1;
            int j=e[i];
            if(!st[j]) {
                q.push(j);
                st[j]=true; //need to be flagged immediately after being queued
            }
        }
    }
}


【算法代码】
下面代码来源于:
https://www.acwing.com/problem/content/video/1075/

/*
d1[u]:从当前结点 u 向下走的最长路径长度
d2[u]:从当前结点 u 向下走的次长路径长度
up[u]:从当前结点 u 向上走的最长路径长度
p1[u]:从当前结点 u 向下走的最长路径是从哪个结点开始的
p2[u]:从当前结点 u 向下走的次长路径是从哪个结点开始的
*/

#include <bits/stdc++.h>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=1e4+5;
const int M=N<<1;
int val[M],e[M],ne[M],h[N],idx;
int d1[N],d2[N],up[N],p1[N],p2[N];
int n;

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

int dfs_d(int u,int fa) { //go down
    d1[u]=d2[u]=-inf;
    for(int i=h[u]; i!=-1; i=ne[i]) {
        int j=e[i];
        if(j==fa) continue;
        int d=dfs_d(j,u)+val[i];
        if(d>=d1[u]) {
            d2[u]=d1[u],d1[u]=d;
            p2[u]=p1[u],p1[u]=j;
        } else if(d>d2[u]) d2[u]=d,p2[u]=j;

    }
    if(d1[u]==-inf) d1[u]=d2[u]=0;
    return d1[u];
}

void dfs_u(int u,int fa) { //go up
    for(int i=h[u]; i!=-1; i=ne[i]) {
        int j=e[i];
        if(j==fa) continue;
        if(p1[u]==j) up[j]=max(up[u],d2[u])+val[i];
        else up[j]=max(up[u],d1[u])+val[i];
        dfs_u(j,u);
    }
}

int main() {
    cin>>n;
    memset(h,-1,sizeof(h));
    for(int i=0; i<n-1; i++) {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }

    dfs_d(1,-1);
    dfs_u(1,-1);

    int ans=inf;
    for(int i=1; n>=i; i++) {
        ans=min(ans,max(d1[i],up[i]));
    }
    cout<<ans;

    return 0;
}

/*
in:
5
2 1 1
3 2 1
4 3 1
5 1 1

out:
2
*/




【参考文献】
https://blog.csdn.net/m0_63997099/article/details/137436898
https://zhuanlan.zhihu.com/p/657767879
https://blog.csdn.net/qq_57150526/article/details/128521583
https://www.acwing.com/solution/content/6825/
https://www.acwing.com/problem/content/1077/
https://www.acwing.com/solution/content/163892/
https://www.cnblogs.com/ljy-endl/p/11612275.html




 

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

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

相关文章

nvm 管理多版本 node

1、下载 先不安装node 下载 nvm 1.1.10-setup.zip 解压&#xff1a;nvm&#xff1a;https://nvm.uihtm.com/ 新建nodejs/node、nodejs/nvm文件夹用于存放node版本和nvm安装路径 安装nvm&#xff1a;上述链接有安装教程 查看是否安装成功&#xff1a;重新打开cmd 输入 nvm nv…

西瓜杯CTF(1)

#下班之前写了两个题&#xff0c;后面继续发 Codeinject <?php#Author: h1xaerror_reporting(0); show_source(__FILE__);eval("var_dump((Object)$_POST[1]);"); payload 闭合后面的括号来拼接 POST / HTTP/1.1 Host: 1dc86f1a-cccc-4298-955d-e9179f026d54…

044基于SSM+Jsp的个性化影片推荐系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

鼠标点击触发-----以控制开灯、宝箱触发为例

开灯 当点击时触发开灯效果 &#xff08;不用设置触发器&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine;public class OpenLight : MonoBehaviour {public Transform light;bool isOpen;private void OnMouseDown(){if (!isOpe…

k8s 部署RuoYi-Vue-Plus之server部署

1.先使用项目编排构建镜像, 修改prod使用的mysql, redis地址 获取运行的服务 kubectl get svc -n ruoyi对应连接修改 然后运行打包package命令, 生成jar包, 再打包为docker容器, 上传到所有节点上, 也可以上传到个人私有仓库 2.部署server-deploy.yaml 镜像名自行修改, apiV…

【免费的车间数据监控大屏】车间管理的新利器,让生产效率一目了然

面对生产车间里各种繁杂的数据&#xff0c;你不会还在用Excel敲击一个个无聊的数据吧&#xff1f;怎么不试试生动形象的车间数据看板呢&#xff1f; 在繁忙的车间里&#xff0c;每一寸空间都跳动着生产的脉搏&#xff0c;而车间数据监控看板&#xff0c;就像是这个舞台上的“智…

C++deque容器

文章目录 deque容器概念deque操作deque对象的带参数构造deque头部和末尾的添加移除操作deque的数据存取deque与迭代器deque赋值deque插入deque删除 deque容器概念 deque是双端数组&#xff0c;而vector是单端的。 deque头部和尾部添加或移除元素都非常快速, 但是在中部安插元…

Mysql数据库两表连接进行各种操作

一&#xff0c;创建两个表emp和dept&#xff0c;并给它们插入数据 1.创建表emp create table dept (dept1 int ,dept_name varchar(11)) charsetutf8; 2.创建表dept create table emp (sid int ,name varchar(11),age int,worktime_start date,incoming int,dept2 int) cha…

电脑清理c盘内存空间怎么清理免费 怎么清理c盘的垃圾文件又不删除有用文件

在计算机使用过程中&#xff0c;随着时间的推移&#xff0c;C盘空间可能会被各种临时文件、缓存和无用的注册表项占用。这不仅会导致C盘空间不足&#xff0c;还可能影响计算机的性能。那么怎么样清理C盘内存空间&#xff0c;怎么样清理C盘的垃圾避开系统文件呢&#xff1f; 一…

手机自带录屏在哪?6个软件教你快速进行手机录屏

手机自带录屏在哪&#xff1f;6个软件教你快速进行手机录屏 手机自带的录屏功能可以让你轻松录制屏幕上的内容&#xff0c;记录游戏过程、制作教程或捕捉其他重要时刻。不同品牌的手机可能在不同位置提供录屏功能。以下是一些常见的手机品牌及其录屏功能位置&#xff0c;以及一…

【python 学习】快速了解python内置类型

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、内置类型的介绍1.1 类型体系1.2 空类型和None1.3 布尔值 二、内置类型的运算2.1 布尔运算2.2 比较运算符比较…

Avalonia开发实践(二)——开发带边框的Grid

一、开发背景 在实际开发工作中&#xff0c;常常会用到Grid进行布局。为了美观考虑&#xff0c;会给每个格子加上边框&#xff0c;如下图&#xff1a; 原生的Grid虽然有ShowGridLines属性可以控制显示格子之间的线&#xff0c;但线的样式不能定义&#xff0c;可以说此功能非常…

人声提取软件有哪些?4种人声提取软件轻松提取人声

在数字音乐与视频制作日益盛行的今天&#xff0c;人声提取软件成为了许多创作者不可或缺的工具。无论是想要从复杂的音乐中分离出纯净的人声&#xff0c;还是希望从视频中提取出精彩的对话片段&#xff0c;一款简单有效的人声提取工具尤为重要&#xff0c;下面给大家分享4种简单…

WTM的项目中EFCore如何适配人大金仓数据库

一、WTM是什么 WalkingTec.Mvvm框架&#xff08;简称WTM&#xff09;最早开发与2013年&#xff0c;基于Asp.net MVC3 和 最早的Entity Framework, 当初主要是为了解决公司内部开发效率低&#xff0c;代码风格不统一的问题。2017年9月&#xff0c;将代码移植到了.Net Core上&…

三菱FX3U进阶课程-运动控制讲解

如果你不会用三菱FX3U系列plc做运动控制&#xff0c;不会控制步进电机、不会控制伺服电机&#xff0c;那来学习本课程就对了&#xff0c;课程带你的价值是&#xff1a; 1、究竟PLC是怎么控制得了步进电机、伺服电机的&#xff1f;好奇怪啊&#xff0c;为啥别人会&#xff0c;我…

WANGLS

DHCP 动态主机配置协议 原理 网络 网络是双向的,网络是有方向的 广播;广播是由种类的,广播是有范围的的 租约的建立——租约的相应、租约的选择——租约的完成 租约的建立:租约的请求 有客户端发出 DHCP discover 广播、寻找服务器 租约的响应 收到响应,不是服务器,…

Revit 2025:建筑设计师的得力助手

在这繁忙的现代社会中&#xff0c;建筑设计师们总是追求着更高效、更精确的工具。而Revit 2025&#xff0c;正如一位老友般&#xff0c;默默地陪伴在我们身边&#xff0c;帮助我们实现心中的蓝图。今天&#xff0c;我怀着满腔的热情与感激&#xff0c;向大家介绍这款软件的功能…

越低越好?所以伦敦金至少可以入金多少呢?

投资者要进行黄金投资&#xff0c;市场中有多个品种可以选择。笔者认为&#xff0c;在众多品种之中&#xff0c;伦敦金是一种适应性比较广的黄金投资方式。如果投资者要选择伦敦金作为自己的黄金投资的主要方式&#xff0c;那么有一些就基本的问题是我们需要了解的&#xff0c;…

Retrofit框架源码深度剖析【Android热门框架分析第二弹】

Android热门框架解析&#xff0c;你确定不来看看吗&#xff1f; OkHttp框架源码深度剖析【Android热门框架分析第一弹】 Retrofit框架源码深度剖析【Android热门框架分析第二弹】 什么是Retrofit&#xff1f; 准确来说&#xff0c;Retrofit 是一个 RESTful 的 HTTP 网络请求…

R包:reticulate R对python的接口包

介绍1 R和python是两种不同的编程语言&#xff0c;前者是统计学家发明并且服务数学统计计算&#xff0c;后者则是最万能的胶水语言。随着大数据时代的到来&#xff0c;两者在数据分析领域存在越来越多的共同点且可以相互使用&#xff0c;为了破解二者的编程壁垒&#xff0c;CR…