希望在看这篇文章前你已经对基础的dp有了一定的了解,就算学的不好也能看懂这篇讲解

我们先以一道例题开头:

树形dp知名入门例题:没有上司的舞会
题目链接

树形dp就是以树为基础的dp(树就不用我说了吧,不关是数据结构还是离散数学好像都要学)
这里我们说说怎么存树;

#include<iostream>
#include<math.h>using namespace std;
const int N=6000+10;
int last[N],ne[N],edge[N],cnt;
bool biao[N];
void add(int a, int b){edge[cnt] = b;ne[cnt] = last[a];last[a] = cnt++;
}int main(){int n;cin>>n;//n名员工int a,b;for(int i=1;i<n;i++)//n-1条边{cin>>a>>b;//b是a的直接上司add(a,b);}}

我们模拟一下,假设有这么一棵树

假设我们需要找1的子节点
通过last[a]这个数组,我们可以得到一个cnt,通过这个cnt可以dge[cnt] = b数组得到它的一个子节点b

void add(int a, int b){edge[cnt] = b;ne[cnt] = last[a];last[a] = cnt++;
}

注意这段代码cnt++是最后执行的
其实我们也可以这么写

void add(int a, int b){cnt++;//此时cnt是从一开始,遍历时需要注意一下edge[cnt] = b;ne[cnt] = last[a];last[a] = cnt;
}

我们甚至还可以这么写

void add(int a, int b){edge[cnt] = b;ne[cnt] = last[a];last[a] = cnt;cnt++;
}

我们注意在最后cnt的值服给last[a]时,last[a]的值是上一次a作为父节点时cnt的值,而我们在改变last[a]为此时cnt的值之前我们已经把它赋值给了ne[cnt] 而这个cnt又赋值给了last[a];
总结下:通过last[a]得到cnt,通过edge[cnt]可以得到一直子节点,通过ne[cnt]可以得到上一次以a作为父节点时的cnt,以此类推

学会了建树,我们可以开始看看这道题了;
还是这课树


假设我们选了1,所求的最大值就是左边子树不选2时的最大值加上右边子树不选3时的最大值最后加上1的权值;
假设我们不选1,所求最大值就是max(左边子树选2,左边子树不选2)+max(右边子树选3,右边子树不选3);
就得到了节点1的最大值,所有节点都可以根据这个方程求得该状态的最大值;
下面我们看看代码:
c++代码

#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;
const int N=6000+10;
int last[N];
int ne[N],edge[N],cnt=1;
bool biao[N];
void add(int a, int b){edge[cnt] = b;ne[cnt] = last[a];last[a] = cnt++;
}
int dp[N][2];int a[N];
void dps(int root)
{dp[root][0]=0;//不选root号节点;dp[root][1]=a[root];//选root号节点for(int i=last[root];i>=1;i=ne[i]){int j=edge[i];dps(j);dp[root][0]+=max(dp[j][0],dp[j][1]);dp[root][1]+=dp[j][0];}}int main(){int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];//因为0包含的有边int x,y;for(int i=1;i<n;i++)//n-1条边{cin>>x>>y;//y是x的直接上司add(y,x);biao[x]=true;//a有父节点b}int v=1;while(biao[v])v++;//找到没有父节点的点dps(v);cout<<max(dp[v][1],dp[v][0]);
}

java代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;public class Main{static int N = 6010;static int[] happy = new int[N];static int[] h = new int[N];static int[] e = new int[N];static int[] ne = new int[N];static int idx = 0;static int[][] f = new int[N][2];static boolean[] has_fa = new boolean[N];static void add(int a,int b){e[idx] = b;ne[idx] = h[a];h[a] = idx ++;}static void dfs(int u){f[u][1] = happy[u];for(int i = h[u]; i != -1;i = ne[i]){int j = e[i];dfs(j);f[u][1] += f[j][0];f[u][0] += Math.max(f[j][1], f[j][0]);}}public static void main(String[] args) {Scanner scan = new Scanner(System.in);int n = scan.nextInt();for(int i = 1;i <= n;i ++) happy[i] = scan.nextInt();Arrays.fill(h, -1);for(int i = 0;i < n - 1;i ++){int a = scan.nextInt();int b = scan.nextInt();add(b,a);has_fa[a] = true;}int root = 1;while(has_fa[root]) root ++;dfs(root);System.out.println(Math.max(f[root][0], f[root][1]));}
}

同理我们看看这道题:
题目链接

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 100010,M=N*2;
int h[N],e[M],ne[M],w[N],idx;
int n;
LL f[N];
void add(int a,int b)
{e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int father)
{f[u]=w[u];for(int i=h[u];~i;i=ne[i]){int j = e[i];if(j!=father)//不能让它倒回去{dfs(j,u);f[u]+=max(0ll,f[j]);}}
}int main()
{cin>>n;memset(h,-1,sizeof h);for(int i=1;i<=n;++i)cin>>w[i];for(int i=0;i<n-1;++i){int a,b;cin>>a>>b;add(a,b);add(b,a);}dfs(2,-1);LL res = f[1];for(int i=2;i<=n;++i)res = max(res,f[i]);cout<<res<<endl;return 0;
}

java代码:

import java.util.*;public class Main {private static int n;private static long res;private static long[] w;private static List<Integer>[] g;private static long[] f ;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n =sc.nextInt();w = new long[n+1];g = new ArrayList[n+1];f = new long[n+1];for(int i = 0;i < n+1; i++){g[i] = new ArrayList<Integer>();}for(int i = 1;i <= n;i ++){w[i] = sc.nextLong();}for(int i = 0;i < n - 1;i ++){int a = sc.nextInt();int b = sc.nextInt();g[a].add(b);g[b].add(a);}dfs(1,0);res = f[1];for(int i = 2; i < n+1; i++){if(res<f[i]){res = f[i]; }}System.out.println(res);}/***root作为根所代表的子树有一个最大权和,将其存储在f[root]中*/private static void dfs(int root,int father){f[root] = w[root];for(int i = 0; i < g[root].size(); i++){Integer child = g[root].get(i);if(child == father){continue;}dfs(child,root);if(f[child] > 0){f[root] += f[child];}}}
}

树形dp讲解(你不会后悔点进来)相关推荐

  1. 通俗易懂讲解树形DP

    在做二叉树的题目的时候,如果你觉得和动态规划有点像,那就用动态规划的思想来做,然后树的遍历是后序遍历的,和动态规划由底向上的思想不谋而合 「动态规划」同样可以作用在树形结构上,这样的问题被称为树形 D ...

  2. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  3. layui树形父子不关联_DP专题7 | 没有上司的舞会 洛谷1352(树形DP)

    高能预警:这是一篇超过5分钟的学习文章,暑假了可以多学会 本篇继续咱们的DP专题,树形DP入门.动态规划每一个类型的DP都是深坑,期望童鞋们自己在这个系列的基础上多花时间进行拓展,学习愉快~ 在讨论树 ...

  4. HDU - 2196(树形DP)

    题目: A school bought the first computer some time ago(so this computer's id is 1). During the recent ...

  5. BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP

    题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...

  6. 树形DP --算法竞赛专题解析(17)

    本系列文章将于2021年整理出版,书名<算法竞赛专题解析>. 前驱教材:<算法竞赛入门到进阶> 清华大学出版社 网购:京东 当当      想要一本作者签名书?点我 如有建议, ...

  7. AcWing 1077. 皇宫看守(树形DP + 状态机DP)

    AcWing 1077. 皇宫看守(树形DP + 状态机DP) 一.问题 二.分析 1.思路分析 2.状态表示 3.状态转移 4.循环设计 5.初末状态 三.代码 一.问题 二.分析 1.思路分析 在 ...

  8. BNUOJ 52305 Around the World 树形dp

    题目链接: https://www.bnuoj.com/v3/problem_show.php?pid=52305 Around the World Time Limit: 20000msMemory ...

  9. [树形dp] Jzoj P5233 概率博弈

    Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵n个点的以1为根的有根树,叶子有权值.假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列. 一开始在1号点有 ...

最新文章

  1. 我收藏的技术知识图(每张都是大图)
  2. fasterrcnn深度学习口罩检测
  3. 记忆网络RNN、LSTM与GRU
  4. python更新pip失败-解决Python pip 自动更新升级失败的问题
  5. Linux时间矫正流程,Linux 时间矫正命令
  6. 一千个不用 Null 的理由,你还用?
  7. Java程序员在中年危机的时候,如何避免被“优化”掉呢?
  8. js操作改变原数组的解决方法
  9. ELK技术栈—Kibana
  10. python两个数相加时_怎么用python让两个小数相加
  11. django分页功能 views与templates
  12. 50 家硅谷 IT 公司技术博客
  13. jquery 滚动到某个div_如何使用jQuery获取父元素
  14. wap绿色传奇搭建(纯净版)
  15. 致远项目管理SPM系统与BIM实现信息集成
  16. DHT 爬虫的学习记录
  17. macOS Monterey 12.4 (21F79) 虚拟机 ISO 镜像
  18. 2022-2027年中国虾养殖行业市场调研及未来发展趋势预测报告
  19. 三维点云:学习+了解
  20. 磁盘操作系统(DOS)

热门文章

  1. 给刚刚步入社会准备从事编程工作兄弟姐妹们一些建议...
  2. python保留字的分支结构_下列Python保留字中,不用于表示分支结构的是
  3. SQL Server 2008 存储过程,带事务的存储过程(创建存储过程,删除存储过程,修改存储过...
  4. "北京成功故事"系列报道之四:巴伐利亚啤酒酿造师在北京
  5. Java - 密码学
  6. 新款奔驰S450升级原厂主动式氛围灯+香氛负离子+4D旋转高音
  7. Mobiles Wall – 致力于分享最优质的手机壁纸
  8. 用python爬取网易云评论_Python3爬取网易云音乐评论|python爬虫|python入门|python教程...
  9. 【JAVADAY35】thymeleaf技术的初步使用及基本语法
  10. DOS命令中schtasks命令的简单使用