【学习笔记】详解换根法(换根DP)

news2024/9/23 7:22:32

一.换根DP的概念

1.换根DP是什么?

换根DP,又叫二次扫描,是树形DP的一种。

2.换根DP能解决什么问题?

换根DP能解决不指定根结点,并且根节点的变化会对一些值产生影响的问题。例如子结点深度和、点权和等。如果要 暴力求解出最优解,则我们可以枚举所有的节点为根,然后分别跑一次搜索,这样的时间复杂度会达到 O(n^{2}),显然不可接受。这时可以考虑使用换根DP解决。

3.换根DP与一般的树形DP相比有什么不同?

其相比于一般的树形DP具有以下特点:

  • 树上的不同点作为根,其解不同
  • 为其求解答案,不能单求某点的信息,需要求解每个节点的信息
  • 无法通过一次搜索完成答案的求解,因为一次搜索只能得到一个节点的答案。

二.换根DP的解法

换根dp通常会与树形dp 结合,我们可以先任定一个根节点root,通过树形dp的思想计算出一个答案。但这样求解出的答案只是以root为根的解,并不能确定是不是最优解。于是再考虑当root的子节点作为根节点时,答案怎样变化。一般可以在 O(1) 的时间复杂度内完成答案的转化。这样整道题的时间复杂度就由 O(n^{2}) 降为了 O(n)

总结一下,换根DP总共是三个步骤:

  1. 指定某个节点为根节点
  2. 第一次搜索完成预处理(如子树大小等),同时得到以上述节点为根的解
  3. 第二次搜索进行换根的动态规划,由已知解的节点推出相连节点的解。

如果到了这里还没有听懂的话,不用慌,可以结合下面的例题慢慢理解。

三.例题精讲

1.STA-Station

question

sol

我们先来画一下样例~(这里先假设以1号节点为根)

在这幅图中,siz[i]表示以i节点为根的子树中节点个数(包括i节点本身),而deep[i]表示i在以1号节点为根时的深度(1号节点深度为1)。

注意:代码中其实不需要开deep数组(第一次dfs时可以直接在dfs设置一个变量dep,然后每次递归时直接将以一号节点为根的解加上dep就行了),但是为了方便解释,我还是画上了。

这样,我们就可以得出来以1为根时深度之和(也就是解)为1+2+3+3+3+4+5+5=26。

然后我们就可以进行换根操作(比如此时以1的子节点4号节点为根)

siz我们依然沿用第一次得到的结果,deep我为了方便演示已经更新了。

从中我们可以发现一些规律。这棵树中从前(以1号节点为根时)属于4的子树的节点(2,3,4,5,6,7,8)的深度都减了1,而其他的节点(这里样例中只有1)的深度都加了1。大家可以自行在纸上多画几个换根后的图,加深理解。

归纳一下我们得到的结论:

如果此时要将根节点换成节点x

那么,以x为根时的解就是:

以x的父节点为根的子树的节点数-以x为根的子树的节点数+(总节点数-以点为根的子树的节点数)

              ↑                                                     ↑                                               ↑

以x为根时的解的基数     这些节点的深度都要-1(在这里省略了乘1)     其他的节点的深度都要+1

假设dh[x]代表以x为根时的解,fa为x的父节点

dh[x] = dh[fa] - siz[x] + (n - siz[x])

总结一下:

  • 我们假设此时将根节点换成节点x,则其子树由两部分构成,第一部分是其原子树,第二部分则是1号节点的其他子树
  • 根从1号节点变为节点x的过程中,我们可以发现第一部分的深度降低了1第二部分的深度则上升了1,而这两部分节点的数量在第一次搜索时就得到了(siz数组)。
  • DP公式:dh[x] = dh[fa] - siz[x] + (n - siz[x])

最后还要注意:第二次dfs后我们还要枚举dh[1~n]取其中的最大值才能得到答案!

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int> vec[2000001];
int n,u,v,siz[2000001],dh[2000001],ans;
void dfs(int x,int fa,int dep)
{
  siz[x] = 1;//因为以x节点为根的子树包括x自身
  dh[1] += dep;//求以1节点为根的解
  for(int i = 0; i < vec[x].size(); i++)
  {
    int son = vec[x][i];
    if(son != fa)
    {
      dfs(son,x,dep + 1);
      siz[x] += siz[son];//不断累加子树中的节点个数
    }
  }
}
void dfs_2(int x,int fa)
{
  if(x != 1) dh[x] = dh[fa] - siz[x] + (n - siz[x]);//DP公式
  for(int i = 0; i < vec[x].size(); i++)
  {
    int son = vec[x][i];
    if(son != fa) dfs_2(son,x);
  }
}
signed main()
{
  cin>>n;
  for(int i = 1; i < n; i++)
  {
    cin>>u>>v;
    vec[u].push_back(v);//建树
    vec[v].push_back(u);
  }
  dfs(1,0,1);
  dfs_2(1,0);
  for(int i = 1; i <= n; i++) ans = max(ans,dh[i]);//取以各个节点为根的解的最大值
  cout<<ans;
  return 0;
}

2.[USACO10MAR] Great Cow Gathering G

question

sol

这道题与例题基本是一致的,只是添加了每个节点和每条边的权值,在DP时注意加上与乘上即可,没有什么大的变形。 如果实在不会,可以结合下面的代码理解。

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
struct ff
{
  int len,id;
};
vector<ff> vec[100001];
int n,u,v,siz[1000001],dh[1000001],ans,w,c[1000001],s;
void dfs(int x,int fa)
{
  siz[x] = c[x];//以x为根的1子树是包括x节点本身的,所以siz[x]要初始化成x节点上的奶牛个数
  for(int i = 0; i < vec[x].size(); i++)
  {
    int son = vec[x][i].id;
    if(son != fa)
    {
      dfs(son,x);
      siz[x] += siz[son];//不断累加以子节点为根的子树上的奶牛数
      dh[1] += siz[son] * vec[x][i].len;//因为题目中添加了边权和点权,故不能像sta那题一样直接+dep
    }
  }
}
void dfs_2(int x,int fa)
{
  for(int i = 0; i < vec[x].size(); i++)
  {
    int son = vec[x][i].id;
    if(son != fa)
    {
      dh[son] = dh[x] - siz[son] * vec[x][i].len + (s - siz[son]) * vec[x][i].len;//此处可以自行画图推导一下
      dfs_2(son,x);
    }
  }
}
signed main()
{
  cin>>n;
  for(int i = 1; i <= n; i++)
  {
    cin>>c[i];
    s += c[i];//s:奶牛的总数
  }
  for(int i = 1; i < n; i++)
  {
    cin>>u>>v>>w;
    vec[u].push_back({w,v});//邻接表建双向边
    vec[v].push_back({w,u});
  }
  dfs(1,0);
  dfs_2(1,0);
  ans = 1e18;
  for(int i = 1; i <= n; i++) ans = min(ans,dh[i]);//因为要求深度最小,所以是取解的最小值
  cout<<ans;
  return 0;
}

四.结语

如果您觉得这篇文章不错,就请点赞关注收藏支持一下吖!ヾ(•ω•`)o

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

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

相关文章

河西走廊潜在蒸散发时空格局变化与气象因素的关系_马亚丽_2023

河西走廊潜在蒸散发时空格局变化与气象因素的关系_马亚丽_2023 摘要关键词 1 数据与方法1.1 数据来源1.2 变化趋势分析1.3 定性分析方法1.3.1 主成分分析1.3.2 相关系数1.3.3 通径分析 1.4 定量分析方法1.4.1 敏感系数1.4.2 贡献率计算 2 结果与分析2.1 ET0多年变化特征2.1.1 E…

Linux下tar命令详解

tar #归档命令 格式 • Tar -参数 [args]..... 参数&#xff1a; 必选参数&#xff1a; 辅助参数&#xff1a; 额外参数&#xff1a; # 打包时排除某个文件 tar cf 文件名.tar --exclude路径/文件 路径 注&#xff1a;此处的路径前后需要保持保持一致&#xff0c;统一…

202417读书笔记|《画•大师 阿尔丰斯•穆夏》——在明亮大胆的色调中熠熠生辉

202417读书笔记|《画•大师 阿尔丰斯•穆夏》——在明亮大胆的色调中熠熠生辉 这是读完的第二本或者第三本穆夏的画集。很赞&#xff0c;他的绘画风格&#xff0c;构图&#xff0c;元素&#xff0c;取大自然的月桂树&#xff0c;常青藤&#xff0c;&#x1f319;的不同形态&…

2024PMP考试新考纲-近年真题练一练和很详细解析(1)

前面的几十篇文章中&#xff0c;华研荟主要从PMP相关的教材&#xff08;PMBOK第六版、PMBOK第七版和敏捷实践指南》出发&#xff0c;分类介绍了相关的考试真题&#xff0c;并逐一作了比较详细的解析&#xff0c;部分典型题目还做了提醒和拓展&#xff0c;帮助大家做题的时候知其…

PHP入门指南:起步篇

PHP入门指南&#xff1a;起步篇 PHP入门指南&#xff1a;起步篇什么是PHP&#xff1f;PHP 的优点PHP 开发环境搭建选择本地服务器软件包安装PHP环境配置Web服务器和PHP测试PHP安装 第一个PHP脚本PHP基础语法标记注释变量数据类型常量条件语句循环函数 PHP入门指南&#xff1a;起…

【实战知识】使用Github Action + Nginx实现自动化部署

大家好啊,我是独立开发豆小匠。 先说一下背景~ 我的小程序:豆流便签,目前使用云托管部署后端服务,使用轻量级服务器部署数据库和一些中间件。 因此服务器成本:云托管 + 云服务器 云托管每周花费5元,一个月就是50,一年就是500啊,所以这期准备把云托管优化掉! 1. 需…

docker镜像结构

# 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["java", "-jar"…

IP数据云识别真实IP与虚假流量案例

随着互联网的普及&#xff0c;企业在数字领域面临着越来越复杂的网络威胁。为了保护网站免受虚假流量和恶意攻击的影响&#xff0c;许多企业正在采用IP数据云。本文将结合一个真实案例&#xff0c;深入探讨IP数据云如何成功准确地识别真实用户IP和虚假流量IP&#xff0c;提高网…

tidb节点重启后,服务无法重连

大家好&#xff0c;我是烤鸭&#xff1a; 前几天遇到tidb节点重启后服务无法重连&#xff0c;确切地说是两个服务&#xff0c;一个可以正常重连&#xff0c;一个不行。 问题复现 由于线上执行慢SQL&#xff0c;导致TiDB 单个节点宕机重启。 其中A服务的3个节点和B服务的1个节…

Nicn的刷题日常之杨氏矩阵(三种方法求解,逐级递增详解,手把手教学,建议三连收藏)

目录 1.杨氏矩阵知识普及&#xff1a;什么是样式矩阵 2.题目描述 3.解题 3.1暴力求解&#xff0c;遍历法 3.2巧妙解题&#xff1a;对角元素法 3.3将巧解法封装为函数 4.结语 1.杨氏矩阵知识普及&#xff1a;什么是样式矩阵 杨氏矩阵&#xff0c;是对组合表示理论和…

计算机网络_1.6.3 计算机网络体系结构分层思想举例

1.6.3 计算机网络体系结构分层思想举例 1、实例引入&#xff08;用户在主机中使用浏览器访问web服务器&#xff09;2、从五层原理体系结构的角度研究该实例3、练习题 笔记来源&#xff1a; B站 《深入浅出计算机网络》课程 本节通过一个常见的网络应用实例&#xff0c;来介绍计…

“type-check“ exited with 1.

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

ProcessSlot构建流程分析

ProcessorSlot ProcessorSlot构建流程 // com.alibaba.csp.sentinel.CtSph#lookProcessChain private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)throws BlockException {// 省略创建 Context 的代码// 黑盒…

gorm day1

gorm day1 gorm简介gorm声明模型 代码样例基本来自官方文档 Gorm简介 什么是ORM&#xff1f; 对象关系映射(Objection Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库(如mysql数据库&#xff09;存在的互不匹配现象的计数。简单来说&#xff0c;ORM是通…

【annie/lux 快速下载哔哩哔哩视频】全网最简单,只需要5步!!!

1.首先 现在annie更名为lux 官网地址&#xff1a;https://github.com/iawia002/lux/releases 2.进入官网之后如图所示 3.下载lux软件 4.下载lux 这里需要说明一下 如果不下载这个的话也可以下载视频 但是视频和音频是分开的&#xff0c;你的视频没有声音 5.下载视频

04、全文检索 -- Solr -- 管理 Solr 的 core(使用命令和图形界面创建、删除 core,以及对core 目录下的各文件进行详细介绍)

目录 管理 Solr 的 core创建 Core方式1&#xff1a;solr 命令创建演示&#xff1a;使用 solr 命令创建 Core&#xff1a;演示&#xff1a;命令删除 Core&#xff08;彻底删除&#xff09; 方式2&#xff1a;图形界面创建Web控制台创建CoreWeb控制台删除 Core&#xff08;未彻底…

软件测试学习笔记-测试用例的编写

7中测试分类 按照阶段可划分单元测试、集成测试、系统测试、验收测试。代码可见度划分黑盒测试、灰盒测试、白盒测试 单元测试&#xff1a;针对源代码的测试 集成测试&#xff1a;针对接口进行测试 系统测试&#xff1a;针对功能和非功能的测试 验收测试&#xff1a;公测、内测…

js中执行上下文和执行栈是什么

文章目录 一、执行上下文二、生命周期创建阶段This Binding词法环境变量环境 执行阶段回收阶段 二、执行栈参考文献 一、执行上下文 简单的来说&#xff0c;执行上下文是一种对Javascript代码执行环境的抽象概念&#xff0c;也就是说只要有Javascript代码运行&#xff0c;那么…

关于Django部署

首先了解一下开发环境服务器跟生产环境服务器有何不同。 一、我们通过 python manage.py runserver 启动开发环境服务器&#xff0c;这条命令背后做了哪些事情&#xff1f; 1、首先加载Django项目的设置&#xff08;settings&#xff09; 2、检查数据库迁移&#xff0c;确保数…

这种学习单片机的顺序是否合理?

这种学习单片机的顺序是否合理&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01…