树形DP简介
来源:互联网 发布:秒杀倒计时软件 编辑:程序博客网 时间:2024/06/08 13:52
基本概念
树形DP就是在“树”的数据结构上做动态规划,通过有限次地遍历树,记录相关信息,以求解问题。树形DP有根到叶(常见)和叶到根两个方向,就是将父亲结点的信息向下传递给子结点,或者从子结点向上传递信息给父亲结点。
因为树本身至少就有“子结构”性质(树和子树);也本身就具有递归性。所以在树上DP其实是其所当然的事,相比线性动态规划来讲,转移方程更直观,更易理解。
例题 HDU 1520
题意
有n个人,接下来n行是n个人的价值,再接下来n行给出l,k,说的是l的上司是k。要求l与k不能同时出现,求最大的结点价值和。
思路
dp[rt][1]+=dp[G[rt][i]][0];dp[rt][0]+=max(dp[G[rt][i]][1],dp[G[rt][i]][0]);//G[rt][i]为当前根节点可以到达的孩子
此类题目的关键在于建树,建树的方法也有多种:
可以用链式结构,可以用下面代码示例中的二维动态数组(相当于链表)
也可以用链式向前星(优化空间,以我目前的经验是比vector稍快),但没有普通的邻接表好写
有的题目甚至不需要建树,只需边遍历边递推建好树又有了转移方程,其他的就不怕不怕了
代码示例
#include<bits/stdc++.h>using namespace std;int n;const int maxn=6005;/*struct Edge{ int from,to;}edges[maxn];*/vector<int> G[maxn];int value[maxn];int father[maxn];int dp[maxn][2];void dfs(int rt){ if(!G[rt].size()){ dp[rt][1]=value[rt]; dp[rt][0]=0; return ;//边界 } dp[rt][0]=0; dp[rt][1]=value[rt]; for(int i=0;i<G[rt].size();++i){ dfs(G[rt][i]); dp[rt][1]+=dp[G[rt][i]][0]; dp[rt][0]+=max(dp[G[rt][i]][1],dp[G[rt][i]][0]); } return ;}void init(){ memset(value,0,sizeof(value)); memset(father,0,sizeof(father)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;++i){ G[i].clear(); }}int main(){ ios::sync_with_stdio(false); while(cin>>n) { init(); for(int i=1;i<=n;++i){ cin>>value[i]; } int u,v; while(cin>>u>>v&&(u+v)) { father[u]=v; G[v].push_back(u); } int root=1; while(father[root]){ root=father[root]; } dfs(root); cout<<max(dp[root][0],dp[root][1])<<endl; } return 0;}
阅读全文
1 0
- 树形DP简介
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形DP
- 树形DP
- 树形DP
- 树形dp
- 树形dp
- 树形dp
- 树形dp
- 树形DP
- 树形DP
- 树形DP
- 树形DP
- Neo4j CQL
- javaWEB---servlet简单理解
- 从FMDB到WCDB、微信团队怎么说-
- git命令之git tag 给当前分支打标签
- 密码学中的“盐值 Salt”
- 树形DP简介
- 实现用户自动登录
- 利用动网论坛dvBBS漏洞上传webshell
- Unity3d 基础学习进度(每日更新)
- flume
- 多线程下载,断点下载
- 25muduo_net库源码分析(一)
- 最近用到的一些网页知识,根据解析域名做跳转和iframe加载页面
- Fibonacci