当前位置: 首页 > news >正文

[算法]树形dp

关键词:树形 \(dp\) 概念与应用

树形 \(dp\) 是一种在树上跑 \(dp\) 的算法

在这我们引用 \(\_Lancy\) 大佬的博客中两段话来讲解树形 \(dp\) 概念,那就是
"树形 \(dp\) 是一种很优美的动态规划,真的很优美真的,前提是在你学会它之后。"
"树形 \(dp\) 的主要实现形式是 \(dfs\) ,在 \(dfs\)\(dp...\) "

例题1简化题目就是选节点使权值之和最大,并且选的节点其父节点不能选

本题对于一个节点u有两种选择
1.选择该节点
所以其子节点不能选择 \(f[u][1] = a[u] + \sum_{v \in u} f[v][0]\)
2.不选择该节点
所以子节点可以选择 \(f[u][0] = \sum_{v \in u} \max(f[v][0],f[v][1])\)

#include <bits/stdc++.h>
using namespace std;
const int N = 6e3+10;
int n,a[N],f[N][2];
bool vis[N];
vector<int> g[N];
void dfs(int u){f[u][0]=0;f[u][1]=a[u];for(int v:g[u]){dfs(v);f[u][0]+=max(f[v][1],f[v][0]);f[u][1]+=f[v][0];}
}
int main(){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<n;i++){int k,l;cin>>l>>k;g[k].push_back(l);vis[l]=1;}int root=1;for(int i=1;i<=n;i++){if(!vis[i])root=i;}dfs(root);cout<<max(f[root][0],f[root][1])<<"\n";return 0;
}

例题2:简化题目,有一颗树,选择 \(m+1\) 个节点,并且每个节点选择前提是从该节点到根节点的路径上所有节点必须全部选,最后询问选 \(m+1\) 个节点权值之和的最大值

本题选择节点要满足的条件可以联想到有依赖背包 \(dp\)

#include <bits/stdc++.h>
using namespace std;
const int N = 305;
int n, m, a[N];
vector<int> g[N];
int f[N][N];
void dfs(int u) {f[u][0]=0;f[u][1]=a[u];for(int v:g[u]){dfs(v);for(int j=m+1;j>=1;j--){for(int k=0;k<j;k++){f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);}}}
}
int main() {cin >> n >> m;for(int i=1;i<=n;i++){int x;cin>>x>>a[i];g[x].push_back(i);}memset(f,0xcf,sizeof(f));dfs(0);cout<<f[0][m+1]<<"\n";return 0;
}

例题3:化简题目:求出子树权值之和的最大值

设f[u]为以u为根的子树权值之和最大值
针对每个子节点如果子节点v的f[v]为负数说明没有考虑的必要了
所以每一个节点u可以写成 \(f[u] = \sum_{v \in u} max(0,f[v])\)
由于不知道根是谁,所以需要遍历一遍,若所有值都小于mx(单个节点最大值)就输出mx当作答案

#include <bits/stdc++.h>
using namespace std;
const int N=16100;
int a[N],f[N],mx=-2e9;
vector<int> g[N];
void dfs(int u,int fa){f[u]=a[u];for(int v:g[u]){if(v==fa) continue;dfs(v,u);f[u]+=max(0,f[v]);}
}
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];mx=max(mx,a[i]);}for(int i=1;i<n;i++){int x,y;cin>>x>>y;g[x].push_back(y);g[y].push_back(x);}dfs(1,0);int ans=-2e9;for(int i=1;i<=n;i++){ans=max(ans,f[i]);}if(ans>mx)cout << ans << endl;else cout<<mx;return 0;
}
http://www.jsqmd.com/news/392350/

相关文章:

  • HDFS 与 HBase 的协同工作:实时大数据存储方案
  • 大数据领域的环保科技数据监测
  • 探索大数据领域HBase的安全漏洞与防范措施
  • 2.18学习
  • 实用指南:学习Three.js--缓冲类型几何体(BufferGeometry)
  • 巴菲特的科技股投资转变:与时俱进的智慧
  • 如何获取26T快客空间,揭秘夸克26T扩容底层逻辑
  • glm-ocr ollama使用 python
  • 屏幕元素定位(Grounding) ollama两个模型
  • 新兴市场vs发达市场:股市估值比较
  • 并行编程实战——CUDA编程的内存建
  • Docker Registry私有仓库搭建与使用
  • 京东e卡回收新风口,闲置卡券如何秒变现金? - 京顺回收
  • 单片机嵌入式试题(第33期)你真理解 volatile 了?:嵌入式工程师必懂的底层原理
  • 退役划水二:一些音乐有关的东西
  • DeepSeek+LangGraph构建企业级多模态RAG:从PDF繁琐解析到Agentic智能检索全流程实战
  • 抗饱和处理
  • 完整教程:【Docker入门】Docker原理和安装
  • [SpringBoot]@SpringBootTest标签作用
  • 近日总结以及后续408规划
  • 意义的界面:走向一种空性人文主义的意识科学
  • CPP-Summit-2020 学习:Software Engineering - Principles
  • Python微信小程序家政保姆信息管理 论文
  • Python微信小程序SSM大学体育场馆场地预约
  • Python微信小程序健康饮食养生
  • Python基于微信小程序的物料产品采购供应链管理系统 论文
  • 意义的界面:在认知极限处的思想止步
  • UE5线程进阶(2):
  • ARM汇编语言中的助记符(Mnemonic)是什么?
  • Flutter 列表为什么会卡顿?不仅仅是 ListView 的问题