树形DP(超详细!!!)

1、概念

一、什么是树型动态规划 

树型动态规划就是在“树”的数据结构上的动态规划,平时做的动态规划都是线性的或者是创建在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺推与逆推,而树型动态规划是创建在树上的,因此也相应的有二个方向:      编程

  1. 叶->根:在回溯的时候从叶子节点往上更新信息    
  2. 根 - >叶:每每是在从叶往根dfs一遍以后(至关于预处理),再从新往下获取最后的答案。    

不论是 从叶->根 仍是 从 根 - >叶,二者都是根据须要采用,没有好坏高低之分。数据结构

二、树真的是一种特别特别优美的结构!

用来作动态规划也简直是锦上添花再美不过的事,由于树自己至少就有“子结构”性质(树和子树);自己就具备递归性。因此在树上DP实际上是其所固然的事,相比线性动态规划来说,转移方程更直观更易理解spa

三、难点    

  1. 和线性动态规划相比,树形DP每每是要利用递归+记忆化搜索。    
  2. 细节多,较为复杂的树形DP,从子树,从父亲,从兄弟……一些小的要处理的地方,脑子不清晰的时候作起来颇为恶心    
  3. 状态表示和转移方程,也是真正难的地方。作到后面,树形DP的老套路都也就那么多,难的仍是怎么能想出转移方程,各类DP作到最后都是这样!

2、经典问题

【树的重心/质心】

对于一棵n个结点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小,即删除这个点后最大连通块的结点数最小。那么这个点就是树的重心。 3d

例题:题目大意:对于一棵无根树,找到一个点使得树以该点为根的有根树,最大子树(选择该节点后其子树的最大节点)的节点数最小。blog

解法:任选一个结点为根,把无根树变成有根树,而后设f[i]表示以i为根的子树的结点个数。递归

程序实现:一次DFS,在无根树转有根树的同时计算。对于结点i,子树中最大结点个数为max{f[j]}个结点,i的“上方子树”中有n-f[i]个结点,只需在dfs过程当中找到最大的子树节点,并与其上方的节点数作比较,就能够找出树的重心了。搜索

补充性质: 程序

1.树中全部点到某个点的距离和中,到重心的距离和是最小的;若是有两个重心,那么他们的距离和同样。方法

2.把两个树经过一条边相连获得一个新的树,那么新的树的重心在链接原来两个树的重心的路径上 im

3.把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离

【树的直径】

树的直径: 树的直径是指树的最长简单路。

例题:题目大意:对于一棵无根树,找到树的一条直径。假设边权为1。

解法一:从任意一点u出发搜到的最远的点必定是s、t中的一点,而后在从这个最远点开始搜,就能够搜到另外一个最长路的端点,即用两遍广搜就能够找出树的最长路。

 

解法二:算是树的直径的一个性质,树的直径的长度必定会是某个点的最长距离f[i]与次长距离g[i]之和。最后求出max{f[i]+g[i]}就能够了。 令j是i的儿子,则:

一、若f[j]+dis[i][j]>f[i],则g[i]=f[i],f[i]=f[j]+dis[i][j];//最大值次大值被更新

二、不然,若f[j]+dis[i][j]>g[i],则g[i]=f[j]+dis[i][j];//次大值被更新

 

【树的中心】

首先题意是在一棵树T中输出每一个结点到叶子的最远距离;  

首先第一个dfs求出全部每一个节点i在其子树中的正向最大距离正向次大距离d[i][0]d[i][1](若是i节点在子树中最大距离通过了2号儿子,那么次大距离就是不通过2号儿子的最大距离)。而且还要标记c[i]=j表示节点i在其子树中的最大距离通过了节点j(即j是i的一个儿子)。   

由上步咱们得到了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图能够知道咱们创建的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点链接它的父节点所能到达的最大距离。

因此咱们只要求出反向最大距离d[i][2](即i节点往它的父节点走所能到达的最大距离)就能够知道i节点在整个树中能走的最大距离了。 d[i][2]求法:i节点往它的父节j点走,若是它的父节点的正向最大距离不通过i的话,那么d[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j]. 若是它的父节点的正向最大距离通过i的话,那么d[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向次大距离+ W[i][j].   

上面就是dfs2要求的值。最终f[i]=max(d[i][0],d[i][2])

 

2、普通树形DP

普通的树形DP中,经常会采用叶->根的转移形式,根据父亲的状态,来肯定子节点的状态,若子节点有多个,则须要一一枚举,将子节点(子树)的DP值合并。

P1352 没有上司的舞会

题目描述

某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。如今有个周年庆宴会,宴会每邀请来一个职员都会增长必定的快乐指数Ri,可是呢,若是某个职员的上司来参加舞会了,那么这个职员就不管如何也不愿来参加舞会了。因此,请你编程计算,邀请哪些职员可使快乐指数最大,求最大的快乐指数。

输入输出格式

输入格式:

第一行一个整数N。(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127) 接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。

输出格式:

输出最大的快乐指数。


 经典的树形dp

设f[x][0]表示以x为根的子树,且x不参加舞会的最大快乐值

f[x][1]表示以x为根的子树,且x参加了舞会的最大快乐值

则f[x][0]=sigma{max(f[y][0],f[y][1])} (y是x的儿子)

f[x][1]=sigma{f[y][0]}+h[x] (y是x的儿子)

先找到惟一的树根root 则ans=max(f[root][0],f[root][1])


 

P2015 二叉苹果树

【问题描述】

有一棵苹果树,若是树枝有分叉,必定是分2叉,这棵树共有N个结点,编号为1-N,树根编号必定是1。 如今这颗树枝条太多了,须要剪枝。可是一些树枝上长有苹果。给定须要保留的树枝数量,求出最多能留住多少苹果。

 

【样例输入】

5 2

1 3 1

1 4 10

2 3 20

3 5 20

【样例输出】

21


【思路点拨】

须要保留Q条树枝,即保留j=Q+1个结点。分三种状况讨论:

①所有保留右子树中的j-1个结点;//根结点必须保留

②所有保留左子树中的j-1个结点;

③左子树保留k个结点,则右子树保留j-k-1个结点。

设树根为i,左儿子为l[i],右儿子为r[i],对于①状况,要取得该方案的最大值,须要取得以r[i]为根的子树保留j-1个结点的最大值。②③同理。

f[i][j]:以i为根的树上保留j个节点的最大权值和。

状态转移方程:

初始化:

目标:

 

 

相关文章
相关标签/搜索