树形DP(树形背包+换根DP)

树形DP

  1. 没有上司的舞会

家常便饭了,写了好几遍,没啥好说的,正常独立集问题。

int head[B];
int cnt;
struct node
{
	int v,nxt;
}e[B<<1];
void modify(int u,int v)
{
	e[++cnt].nxt=head[u];
	e[cnt].v=v;
	head[u]=cnt;
}
int a[B];
int f[B][5];
int n;
void dfs(int u,int pre)
{
	for (int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if (v==pre) continue;
		dfs(v,u);
		f[u][1]+=f[v][0];
		f[u][0]+=max(f[v][0],f[v][1]);
	}
}
void work()
{
	cin>>n;
	for (int i=1;i<=n;i++) f[i][1]=read();
	for (int i=1;i<n;i++)
	{
		int v=read(),u=read();
		modify(u,v);
		modify(v,u); 
	}
	dfs(1,0);
	cout<<max(f[1][0],f[1][1]);
}

  1. 选课

树上背包问题。

说说自己犯的错误

  • 式子推得太慢
  • 滚动数组特别容易记混状态,尤其是背包,因为是从大到小更新,如果在枚举到大数的时候发生转移却用的小的,那么更新的答案必然是错误的,这个问题我调了一下午,就是滚动数组的错误,一定切记,对于逆序的滚动数组问题,一定好想好当前所需状态是否已经更新,而不是借用上一维的状态,这种错误最容易犯在背包上!!
  • 这个题目优化点在于,用一个虚拟点来连接森林,这样就不用再写一遍了
#include<bits/stdc++.h>
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
const int B=1e6+10;
const int inf=0x3f3f3f3f;
int T;
int n,m;
int f[309][309];
int dp[309][309];
int a[B];
int head[B];
int cnt;
struct node
{
	int v,nxt;
}e[B<<1];
void modify(int u,int v)
{
	e[++cnt].nxt=head[u];
	e[cnt].v=v;
	head[u]=cnt;
}
int fa[B];
int vis[B];
void dfs(int u,int pre)
{
	f[u][1]=a[u];
	for (int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if (v==pre) continue;
		dfs(v,u);
		
	}
	for (int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if (v==pre) continue; 
		for (int j=m;j>=1;j--)
		{
			for (int k=1;k<=j;k++)
				dp[u][j]=max(dp[u][j],dp[u][j-k]+f[v][k]);
			
			//f[u][j]=dp[u][j-1]+a[u];//因为我们的j是倒序枚举,先更新大的在更新小的,那么dp[u][j-1]并不是当前已经对v
			//点进行操作完毕的 dp,而是上一维度 
		}
		for (int j=1;j<=m;j++) f[u][j]=dp[u][j-1]+a[u];//放在外面就是正确的,这是因为用的是当前维度下的dp,滚动数组容易反的错误 
	}
} 
int ans[B];
int num;
int F[B];
void work()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		fa[i]=read();
		a[i]=read();
		modify(fa[i],i);
		modify(i,fa[i]);
	}
	for (int i=1;i<=n;i++)
	{
		if (!fa[i])
		{
			dfs(i,0);
			ans[++num]=i;
		}
	}
	for (int i=1;i<=num;i++)
	{
		for (int j=m;j>=1;j--)
		{
			int x=ans[i];
			for (int k=0;k<=min(m,j);k++)
				F[j]=max(F[j],F[j-k]+f[x][k]);
		}	
	}
	cout<<F[m]; 
}
int main()
{
	T=1;
	while (T--) work();
	return 0;
}
  1. 积蓄程度

题面:见ACwing287

思路

换根DP的常规思路

  • 有下往上递推一遍
  • 再由上往下递推一遍

我们先来想如果根节点固定的时候如何做,比较容易的DP,其实也就是递推,没有任何决策问题。

d [ u ] d[u] d[u] 表示以 u u u 为根节点的最小流量。通过题目可以知道,一条路径上的流量取决于最小流量边,所以这是一个维护最小值的问题。

转移有
d [ u ] = ∑ min ⁡ { d [ v ] , w } d[u]=\sum \min\{d[v],w\} d[u]=min{d[v],w}
再来考虑如何换根。

先来考虑由根节点换到儿子会发生什么变化

图

我们会发现, d [ 1 ] d[1] d[1] 中需要去掉 d [ 2 ] d[2] d[2] 做出的贡献,即 d [ 1 ] − min ⁡ { d [ 2 ] , w } d[1]-\min\{d[2],w\} d[1]min{d[2],w}

d [ 2 ] d[2] d[2] 需要加入 d [ 1 ] d[1] d[1] 的贡献,即 d [ 2 ] + min ⁡ { d [ 1 ] , w } d[2]+\min\{d[1],w\} d[2]+min{d[1],w}

我来思考,如果是在树中间换根怎么办,我们发现,父亲节点还需要同时加入父亲父亲的节点情况。

在这里插入图片描述

比如绿色部分,可是这条边比较难表示,不容易找到 w w w,如果我们看成 2 2 2 节点就是根节点,不再是父亲节点的时候,此时的值刚好就是 2 2 2 当根的值,我们用 f [ 2 ] f[2] f[2] 表示 2 2 2 为根的最大值。那么在转移的时候我们就不需要考虑由父亲父亲的情况。转移由
f [ v ] = d [ v ] + min ⁡ { w , f [ u ] − min ⁡ { w , d [ v ] } } f[v]=d[v]+\min\{w,f[u]-\min\{w,d[v]\}\} f[v]=d[v]+min{w,f[u]min{w,d[v]}}

对于度数只为1的还需要特别注意,度数唯一不一定是叶子结点,也可能是根节点,当换根时,根节点变成叶子结点, f [ u ] − min ⁡ { w , d [ v ] } f[u]-\min\{w,d[v]\} f[u]min{w,d[v]} 变成 0 0 0 ,实际上应该直接加入边值 w w w,所以需要特别判断。

换根时候的注意点

  • 必须一直保持根和儿子换,而不是父亲和儿子换。
  • 根节点和叶子结点要注意
#include<bits/stdc++.h>
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
const int B=1e6+10;
const int inf=0x3f3f3f3f;
int T;
int n;
int head[B],cnt;
struct node
{
	int v,nxt,w;
}e[B<<1];
void modify(int u,int v,int w)
{
	e[++cnt].nxt=head[u];
	e[cnt].v=v;
	e[cnt].w=w;
	head[u]=cnt;
}
int f[B];
int d[B];
int du[B];
void dfs1(int u,int pre)
{
	for (int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		int w=e[i].w;
		if (v==pre) continue;
		dfs1(v,u);
		if (du[v]!=1) d[u]+=min(d[v],w);
		else d[u]+=w;
	}
} 
void dfs2(int u,int pre)
{
	for (int i=head[u];i;i=e[i].nxt)
	{
		int w=e[i].w;
		int v=e[i].v;
		if (v==pre) continue;
		if (du[u]==1) f[v]=d[v]+w;
		else f[v]=d[v]+min(w,f[u]-min(d[v],w));
		dfs2(v,u);
	}
}
void work()
{
	cin>>n;
	cnt=0;
	memset(head,0,sizeof(head));
	for (int i=1;i<=n;i++)
	{
		f[i]=0;
		d[i]=0;
		du[i]=0;
	}
	for (int i=1;i<n;i++)
	{
		int u=read(),v=read(),w=read();
		modify(u,v,w); du[u]++; du[v]++;
		modify(v,u,w);
	}
	dfs1(1,0); f[1]=d[1];
	dfs2(1,0);
	int ans=0;
	for (int i=1;i<=n;i++) ans=max(ans,f[i]);
	cout<<ans<<"\n";
}
int main()
{
	T=read();
	while (T--) work();
	return 0;
}
/*
1
3
1 2 1
2 3 1
*/ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于 Python 的项目管理系统开发

基于 Python 的项目管理系统开发 一、引言 在当今快节奏的工作环境中&#xff0c;有效的项目管理对于项目的成功至关重要。借助信息技术手段开发项目管理系统&#xff0c;能够显著提升项目管理的效率和质量。Python 作为一种功能强大、易于学习且具有丰富库支持的编程语言&…

紫光同创开发板使用教程(二):sbit文件下载

sbit文件相当于zynq里面的bit文件&#xff0c;紫光的fpga工程编译完成后会自动生成sbit文件&#xff0c;因工程编译比较简单&#xff0c;这里不在讲解工程编译&#xff0c;所以我这里直接下载sbit文件。 1.工程编译完成后&#xff0c;可以看到Flow列表里面没有报错&#xff0c…

完美解决:.vmx 配置文件是由 VMware 产品创建,但该产品与此版 VMware Workstation 不兼容

参考文章&#xff1a;该产品与此版 VMware Workstation 不兼容&#xff0c;因此无法使用 问题描述 当尝试使用 VMware Workstation 打开别人的虚拟机时&#xff0c;可能会遇到以下报错&#xff1a; 此问题常见于以下场景&#xff1a; 从其他 VMware 版本&#xff08;如 ESX…

QQ登录测试用例报告

QQ登录测试用例思维导图 一、安全性测试用例 1. 加密传输与存储验证 测试场景&#xff1a;输入账号密码并提交登录请求。预期结果&#xff1a;账号密码通过加密传输&#xff08;如HTTPS&#xff09;与存储&#xff08;如哈希加盐&#xff09;&#xff0c;无明文暴露。 2. 二…

Docker内存芭蕾:优雅调整容器内存的极限艺术

title: “&#x1f4be; Docker内存芭蕾&#xff1a;优雅调整容器内存的极限艺术” author: “Cjs” date: “2025-2-23” emoji: “&#x1fa70;&#x1f4a5;&#x1f4ca;” 当你的容器变成内存吸血鬼时… &#x1f680; 完美内存编排示范 &#x1f4dc; 智能内存管家脚本…

计算机毕业设计SpringBoot+Vue.jst网上购物商城系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

IoT设备硬件攻击技术与接口漏洞利用

IoT设备硬件攻击技术 0x01 总线与接口概述 1.1 UART 概述 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;是一种常见的串行通信协议&#xff0c;广泛用于嵌入式设备中进行调试和数据传输。它通过两根信号线&#xff08;TX和RX&#xff09;实现异…

Windows程序设计29:对话框之间的数据传递

文章目录 前言一、父子对话框之间的数据传递1.父窗口获取子窗口数据2.子窗口获取父窗口数据 二、类外函数调用窗口的操作1.全局变量方式2.参数传递方式 总结 前言 Windows程序设计29&#xff1a;对话框之间的数据传递。 在Windows程序设计28&#xff1a;MFC模态与非模态对话框…

敏捷开发07:敏捷项目可视化管理-ScrumBoard(Scrum板)使用介绍

ScrumBoard(Scrum板)介绍 ScrumBoard&#xff08;Scrum板&#xff09;是敏捷项目管理中使用的可视化工具&#xff0c;用于跟踪和监控冲刺阶段的任务进度。 主要通过可视化的看板来管理工作&#xff0c;它可视化了敏捷开发中的工作流程、任务状态、团队角色。 Scrum 团队在各…

【每日八股】Redis篇(一):概述

Redis 为什么快&#xff1f; 一句话概括&#xff1a; Redis 之所以快&#xff0c;主要是因为它是基于内存操作的&#xff0c;避免了磁盘 I/O 的开销&#xff1b;采用单线程模型&#xff0c;避免了上下文切换和锁竞争&#xff1b;使用了高效的数据结构和紧凑的编码方式&#xf…

蓝桥杯——按键

一&#xff1a;按键得原理图 二&#xff1a;按键的代码配置 step1 按键原理图对应引脚配置为输入状态 step2 在GPIO中将对应引脚设置为上拉模式 step3 在fun.c中写按键扫描函数 写完后的扫描函数需放在主函数中不断扫描 扫描函数主要通过两个定义变量的值来判断&#xf…

语音控制热水器WTK69000离线语音识别芯片方案:迈向智能家居新时代

一、开发背景 在传统热水器使用中&#xff0c;人们往往需要手动调节水温、选择模式&#xff0c;这不仅操作繁琐&#xff0c;而且容易因误操作导致不必要的能源浪费。为了改善这一现状&#xff0c;热水器厂商开始引入语音识别技术。通过语音识别芯片&#xff0c;热水器能够准确识…

演示基于FPGA的视频图像去雾处理效果

我近期用FPGA开发板做了一个视频图像去雾算法模块&#xff0c;用于验证其能否在不进行帧缓冲的情况下实现去雾功能。 去雾算法来自一篇技术资料&#xff08;私信提供篇名&#xff09;&#xff0c;其基础是近似的大气光模型。 1 算法原理概要 借助RGB直角坐标空间中的光矢量分…

UE_C++ —— Gameplay Tags

目录 一&#xff0c;Defining Gameplay Tags Adding Tags in Project Settings Importing Tags from Data Table Assets Defining Tags with C 二&#xff0c;Using Defined Gameplay Tags Applying Tags to Objects Evaluating Tags with Conditional Functions 三&am…

计算机视觉算法实战——三维重建(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ 1. 三维重建领域简介 三维重建&#xff08;3D Reconstruction&#xff09;是计算机视觉的核心任务之一&#xff0c;旨在通过多视角图像、视频…

Spring5框架八:整合Mybatis

精心整理了最新的面试资料&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 1、导入相关的jar包 <dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>…

AI学习第一天-什么是AI

AI的发展可以被分为四次浪潮&#xff0c;这包括符号主义、机器学习与神经网络&#xff0c;以及深度学习。在这些发展中&#xff0c;深度学习凭借其在处理非结构化复杂数据、强大的学习能力和可解释性方面的优势备受关注。深度学习技术的应用不仅提升了AI系统的性能&#xff0c;…

redis-bitmap使用场景

bitmap原理 Bitmap&#xff08;位图&#xff09;是一种基于二进制位的数据结构&#xff0c;用于高效地存储和操作大量的布尔值 可以对单个位进行读写操作 demo package org.example;import org.redisson.Redisson; import org.redisson.api.RBitSet; import org.redisson.ap…

华为 网络安全 认证

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 华为 网络安全 认证&#xff1a;保障信息安全的重要一环 在数字化时代的今天&#xff0c;网络安全成为了企业和个人都需要高度重视的问题。尤其是在企业信息化的…

ubuntu22.04连接github无法访问的问题

目录 说明安装 说明 此方案只针对虚拟机, 如果是云服务器(毕竟是官方维护, github还是能访问到的)多试几次肯定能够访问到的. 国内我们无法访问外网, 所以我们目前能够访问外网的途径基本上只能开佳速器. 所以我们需要选择一款加速器来帮助我们访问外网, 目前市面上很多佳速器…