【算法学习笔记】换根DP -- java代码实现

11.动态规划:树形DP问题、树上最大独立集、树上最小支配集、换根DP、树上倍增(LCA)【灵神基础精讲】 来源0x3f:https://space.bilibili.com/206214 阅读详情

1. 问题描述

给定一个无向、连通的树。树中有 n 个标记为 0…n-1 的节点以及 n-1 条边 。
给定整数 n 和数组 edges , edges[i] = [aia_iai​, bib_ibi​]表示树中的节点 aia_iai​ 和 bib_ibi​ 之间有一条边。
返回长度为 n 的数组 answer ,其中 answer[i] 是树中第 i 个节点与所有其他节点之间的距离之和。

1.1 例子说明

在这里插入图片描述
输入: n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
输出: [8,12,6,10,10,10]
解释: 树如图所示。我们可以计算出 dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
也就是 1 + 1 + 2 + 2 + 2 = 8。 因此,answer[0] = 8,以此类推。

2. 思路

一开始看到往往想所有节点都做一遍根,然后各自深度优先遍历一下,这样做的时间复杂度O(n2)O(n^2)O(n2),那能不能有什么方法优化一下呢,这时候就引出要讲的换根DP算法:
在这里插入图片描述
上面的图片分别是以0和2作为根节点,然后到其余各个节点的距离和,我们可以发现当改变根时候只有新根及其子树会减少路径,而其余节点会相应增加路径(下移了)
所以我们可以得到 ans[2] = ans[0] + 2 - 4 ,此时我们就可以省去很多的计算时间,但是需要注意的是这种方法需要得到每一个节点的子树!!,这个我们可以在第一遍dfs的时候做


将上式进行一个抽象我们就可以得到递推方程

  1. 假设当前根节点是x,而下一个做根节点的是y。
  2. 假设第 i 个节点的子树记录在size数组中(非i节点的所有子树就是 n-size[i] )。则有:

ans[y] = ans[x] +n - size[y] - size[y]
          ~~~~~~~~~~           = ans[x] +n - 2*size[y]
即为核心公式!!

2.2 算法流程

  1. 从 0 出发进行 DFS,累加 0 到每一个点的距离,得到初始 ans[0]~ans[0] ans[0]
  2. DFS同时计算子树的大小 size[i]size[i]size[i]
  3. 第二遍从 0 出发 DFS,设 yyy 是 xxx 的儿子,那么有:ans[y]=ans[x]+n−2∗size[y]ans[y] = ans[x] +n - 2*size[y]ans[y]=ans[x]+n−2∗size[y]
  4. 递归得到每一个 ans[i]~ans[i] ans[i]

3. 代码实现

class Solution {

    private List<Integer>[] g;

    private int[] ans, size;



    public int[] sumOfDistancesInTree(int n, int[][] edges) {

        g = new ArrayList[n]; // g[x] 表示 x 的所有邻居

        Arrays.setAll(g, e -> new ArrayList<>());

        for (var e : edges) {

            int x = e[0], y = e[1];

            g[x].add(y);

            g[y].add(x);

        }

        ans = new int[n];

        size = new int[n];

        dfs(0, -1, 0); // 0 没有父节点

        reroot(0, -1); // 0 没有父节点

        return ans;

    }



    private void dfs(int x, int fa, int depth) {

        ans[0] += depth; // depth 为 0 到 x 的距离

        size[x] = 1;

        for (int y : g[x]) { // 遍历 x 的邻居 y

            if (y != fa) { // 避免访问父节点

                dfs(y, x, depth + 1); // x 是 y 的父节点

                size[x] += size[y]; // 累加 x 的儿子 y 的子树大小

            }

        }

    }



    private void reroot(int x, int fa) {

        for (int y : g[x]) { // 遍历 x 的邻居 y

            if (y != fa) { // 避免访问父节点

                ans[y] = ans[x] + g.length - 2 * size[y];

                reroot(y, x); // x 是 y 的父节点

            }

        }

    }

}
拯救者R7000P(2021)装双系统Ubuntu20.04 解决联发科MT7921无线网卡在Ubuntu中不能联网 拯救者R7000P(2021)装双系统Ubuntu20.04/Ubuntu18.04 电脑配置:联想拯救者R7000P CPU:AMD R7-5800H GPU:RTX3060-6G 内存:16GB 固态:500G(原装)+500(加装) 1.做系统盘(本文以Ubuntu20.04为例) 1.下载Ubuntu20.04镜像 直接去Ubuntu官网或者一些国内的镜像去下载都可以,这里给出一个网址https://ubuntu.com/download/desktop,根据需要下载自己学要的Ubuntu版本,后缀 阅读详情

相关推荐

手把手教你利用qemu搭建银河麒麟V11 arm环境

在Windows环境下,初学者或企业用户常通过VMware、VirtualBox等虚拟机软件安装Ubuntu、Red Hat等Linux系统,这类工具更侧重X86等复杂指令集架构(CISC,常见于Intel、AMD处理器)的虚拟化。而QEMU是一款开源的虚拟机监视器与模拟器,核心优势在于可模拟ARM、MIPS、RISC-V等精简指令集架构(RISC)的处理器并提供虚拟化能力,更适合对虚拟化技术有一定了解的用户。可能是电脑性能问题,安装过程比较慢,需要耐心等待。等操作系统下载完成后,进行安装了。

huanhuanzhou blog 2455

leetcode【每日一题】834. 树中距离之和【未解决

题干 给定一个无向、连通的树。树中有 N 个标记为 0…N-1 的节点以及 N-1 条边 。 第 i 条边连接节点 edges[i][0] 和 edges[i][1] 。 返回一个表示节点 i 与其他所有节点距离之和的列表 ans。 示例 1: 输入: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]] 输出: [8,12,6,10,10,10] 解释: 如下为给定的树的示意图: 0 / \ 1 2 /|\ 3 4 5 我们可以计算出 dist

qq_43491066的博客 260

嵌入式Linux Qt应用程序卡死问题分析记录

根据应用和系统层面的分析,软件功能异常和卡死现象的原因是系统控制台/dev/console阻塞导致依赖其的相关应用和命令异常。系统控制台/dev/console阻塞的原因还未确定,最近的软件版本和其他测试同事未出现该问题,所以很大可能是串口线的问题,待后续有进展了继续更新。

V10_x的博客 1643

2023-05-05:给定一个无向、连通的树 树中有 n 个标记为 0...n-1 的节点以及 n-1 条边 。 给定整数 n 和数组 edges , edges[i] = [ai, bi]表示树中的

2023-05-05:给定一个无向、连通的树树中有 n 个标记为 0…n-1 的节点以及 n-1 条边。给定整数 n 和数组 edges ,edges[i] = [ai, bi]表示树中的节点 ai 和 bi 之间有一条边。返回长度为 n 的数组 answer ,其中 answer[i] :树中第 i 个节点与所有其他节点之间的距离之和。输入: n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]。输出: [8,12,6,10,10,10]。

福大大架构师每日一题 2万+

从球谐函数到哈希编码:Instant-NGP如何重构NeRF的数学基础

本文深入解析了Instant-NGP如何通过多分辨率哈希编码重构NeRF的数学基础,显著提升训练速度和渲染效率。对比传统球谐函数,哈希编码在计算复杂度、频率适应性和内存访问效率上具有明显优势,为实时神经渲染技术开辟了新方向。

weixin_29240711的博客 419

统信UOS服务器上,达梦DM8数据库安装避坑全记录(附大小写敏感设置)

本文详细介绍了在统信UOS服务器版上部署达梦DM8数据库的全过程,包括环境准备、安装流程、数据库实例初始化及关键参数配置,特别是大小写敏感设置的注意事项。提供了从系统配置到性能优化的完整指南,帮助用户避免常见问题,确保数据库稳定运行。

weixin_30647423的博客 332

【二次扫描与换根】总结

在一棵无根树上需要以多个节点为根求解答案,可以运用。具体操作是通过实现一次自底向上的深度优先搜索和一次自顶向下的深度优先搜索来计算“换根”后的解。

cqbzliuhongyi的博客 1028

Authentication Assertion Tickets,SAP 系统到系统单点登录里的短命凭证

SAP 系统间的身份传递机制存在 Authentication Assertion Ticket 和 SAP Logon Ticket 两种易混淆的凭证。前者用于系统间短时身份委托(有效期2分钟,通过HTTP头传输),后者用于浏览器SSO(可配置有效期,通过Cookie传输)。Assertion Ticket依赖签发系统的数字签名和严格的时间同步,适用于ABAP/Java系统间的后台作业调用。现代SAP架构已转向OAuth 2.0等标准协议,但老系统中仍需注意两种票据的关键差异:传输方式、有效期、接收方限制

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 602

LeetCode 834 树中距离之和 题解

LeetCode 834 树中距离之和 题解 LeetCode链接 给定一个无向、连通的树。树中有 N 个标记为 0...N-1 的节点以及 N-1 条边 。 第 i 条边连接节点 edges[i][0] 和 edges[i][1] 。 返回一个表示节点 i 与其他所有节点距离之和的列表 ans。 示例 1: 输入: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]] 输出: [8,12,6,10,10,10] 解释: 如下为给定的树的示意图: 0 / \

qq_39618369的博客 365

VS Code 重大更新:Agent Skills完美支持!

代码不会骗人,但你的 LLM 可能会编个故事——除非你给它一本《技能手册》。——某位深夜调试成功的 Go 工程师。

weixin_44058951的博客 3459

“华为杯“第十四届中国研究生数学建模竞赛-E题:多波次导弹发射中的规划问题(续)(附MATLAB代码实现)

将最长暴露时间的发射装置按照“优先隐蔽于转载地”,即增加该种发射装置的隐蔽时长,从而达到缩短最长暴露时间的目的。8.2 模型建立。

getusushu的博客 298

JAVA程序设计:树中距离之和(LeetCode:834)

给定一个无向、连通的树。树中有 N 个标记为 0...N-1 的节点以及 N-1条边。 第 i 条边连接节点edges[i][0] 和 edges[i][1]。 返回一个表示节点 i 与其他所有节点距离之和的列表 ans。 示例 1: 输入: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]] 输出: [8,12,6,10,10,10] 解...

信仰.的博客 590

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

换 根 dp

1.首先 dfs1 得到每个节点子树的节点个数,然后得到dp[1](以1节点为根的答案),dp[子]=dp[父] - size[子] + n - size[子] 得到其相邻子节点的答案。2.假设以u为根节点的收益是dp[u],如果以v为根节点,对于以u为根,r染色v时收益增加n-size[v];2.设置sum数组:固定某个节点为根节点(比如下图以1为根节点),各节点到其子树所有节点的距离和,得到sum[1],就是dp[1]用下题引入换根dp:简而言之换根dp就是通过父节点的答案得到相邻子节点的答案。

2301_80275822的博客 403

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

2019江西省省赛 Cotree[换根dp]

【题目】 hdu6567 题目连接http://acm.hdu.edu.cn/showproblem.php?pid=6567 Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 336Accepted Submissio...

ccsu_deer 572

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

2019 Multi-University Training Contest 8 1006 换根dp 维护最大值最小值

Acesrc and Travel Time Limit: 2000/2000 MS (Java/Others)Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1394Accepted Submission(s): 368 Problem Description Acesrc is a fa...

ccsu_deer 622

算法笔记-换根DP

换根DP

m0_53899788的博客 557

poj3585树最大流——换根法

题目:http://poj.org/problem?id=3585 二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案。 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std;...

aodan5477的博客 191

[题解] P1850 换教室 Floyd+DP

P1850 换教室 Floyd+DP题解 洛谷题目链接 牛客题目链接

qq_46636543的博客 204

换根DP-树的最长路径、区间DP-石子合并、状态压缩-最短Hamilton路径、数位DP-234的和(模板)

换根DP-树的最长路径、区间DP-石子合并、状态压缩-最短Hamilton路径、数位DP-234的和(模板)

2302_80720472的博客 188

动态规划算法(DP) JAVA 菜鸟理解

  不知道动态规划是啥,搜索到这篇动态规划算法(DP) 现在把java版的动态规划理解记录一下 题目描述 给你六种面额1、5、10、20、50、100元的纸币,假设每种币值的数量都足够多,编写程序求组成N员(N为0-10000的非负整数)的不同组合的个数。 输入描述: 输入为一个数字N,即需要拼凑的面额 输出描述: 输出也是一个数字,为组成N的组合个数。 首先一个先有一个DP表格的想法...

HURRYMK的博客 9465

数据结构与算法 - 子数组最大和(Kadane算法):DP的简化实现

文章摘要 本文介绍了Kadane算法求解子数组最大和问题。该算法以动态规划思想为基础,通过维护当前子数组和(currentSum)和全局最大值(maxSum)实现O(n)时间复杂度和O(1)空间复杂度的最优解。文章详细解析了算法原理,包括状态转移方程、Java实现代码和可视化执行过程,并拓展了记录子数组位置的变种问题。通过数学归纳和贪心策略的双重视角,作者论证了算法的正确性,使读者能够深入理解这一经典算法的核心思想与实用价值。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

dp知识点合集

使用链式前向星的方式。

yyh2333666的博客 382

数据结构与算法 - 打家劫舍问题:DP状态转移的逻辑推导

定义dp[i]抢劫前i+1个房子(即nums[0..i])所能获得的最大金额。i从 0 开始。dp[i]表示考虑nums[0]到nums[i]时的最优解。打家劫舍问题虽然场景简单,但其背后的 DP 思想非常深刻。通过“抢”与“不抢”的二元决策,我们构建了清晰的状态转移逻辑,并通过空间优化提升了效率。更重要的是,它展示了如何将一个全局优化问题,分解为一系列局部最优决策。算法的魅力,在于用逻辑和数学解决现实问题。打家劫舍问题,就像一个微型的“人生决策模型”:在约束条件下,如何做出最优选择?

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

JAVA:实现Knapsack背包问题算法(附带源码)

JAVA:实现Knapsack背包问题算法(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1295

Java实现 算法训练 K好数 (动态规划dp)

动态规划的思路: 定义数组dp[i][j]表示位(长度)是i,结尾数字是j的K好数的个数。当i=1时,即长度为1时,所有的数字都是K好数,因为没有数字相邻的情况。但是因为开头数字是i,所以要注意第一个数字不能是0,所以赋值时从1开始,最大为k-1。动态规划转移方程为dp[i][j]+=dp[i-1][m]。其实就是从第一个数字开始,逐个找出后面的数字不能与前一个数字相邻的情况有多少种,直到i=l...

伤感的博客 706

算法题 树中距离之和

本文提出了一种基于两次DFS的高效算法,用于计算树中每个节点到其他所有节点的距离之和。该方法通过第一次DFS后序遍历计算子树大小和初始距离和,再利用第二次DFS前序遍历进行换根动态规划,将时间复杂度优化至O(n)。算法通过邻接表存储树结构,利用子树大小和父节点结果推导子节点结果,最终得到每个节点的距离和数组。示例展示了该算法在6节点树上的计算过程,验证了其正确性。

红血哥 741
上一篇: 埃氏筛 -- 范围内找质数经典算法java实现
下一篇: 图像的全局信息和局部信息对训练的好处
美味不是堡
博客等级 码龄6年 2009粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值