树形DP总结 树形dp例题 树形背包总结 树形背包例题

树形DP

DP[i][j] 一般第一维表示节点编号(代表以此节点为根节点的子树)  对于每个节点,一般先递归处理他的子节点,在回溯时对根节点转移, 在做树形dp的题目的时候,最优子结构体现的非常明显。

树形背包

树形背包除了以节点编号作为第一维,通常我们也像线性dp那样,把当前背包的体积作为第二维,在状态转移时,我们处理的就是一个分组背包(每组至少取一个)问题,注意在进行状态转移时要保证一个儿子节点只可以转移一种状态

树形DP题目

HDU 1520 Anniversary party

题意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?

思路:由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优。其实不然,有可能父节点和子节点都不选,而要选子孙节点。不过只要再往深点想下,就可以得出动态规划的解法。每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那我们只要从叶子节点往根结点不断更新dp[i][0]和dp[i][1]就可以了。
dp[u][0]+=max(dp[v][0],dp[v][1]);      dp[u][1]+=dp[v][0];

HDU 2196 Computer

题意:给一棵树,每条树边都有权值,问从每个顶点出发,经过的路径权值之和最大为多少?每条树边都只能走一次

思路:节点u   最大值有二个可能  二个儿子节点的最长链 或者 一个儿子节点最长链和父亲节点最长链(不包括节点u)

二个儿子节点的最长链可以很容易求出来,但是父亲节点的最长链就求不出来了,但是如果我们知道父亲节点的 二个最大儿子节点链呢?进行二次dfs即可 第一次dfs求出每个节点的二个儿子 最长链 第二次dfs利用第一次dfs求出来的二个最长链跟新就行了

CodeForces  219D Choosing Capital for Treeland

题意:给一颗树,树的边是有向的,让你选一个节点,这个节点能到达所有的节点,问你最少要反转多少条边

思路:dp[u] 表示以u为根节点最少要反转的边数,假设节点u为根节点,状态转移方程很容易想到,dp[u]+= dp[v]  +(u,v)是否要反转 +dp[f(v)] +(u,f)是否要反转  dp[v]我们可以求出来,但是dp[f(u)]我们求不出来,和上题一样,先一个dfs求出dp[u],然后再用一个dfs求答案

HDU  3586 Information Disturbing

题意:有一颗树,1是根节点,每个边切断有一个花费,要切断一些边,使叶子节点和根节点没有联系,求在切断的边总花费小于m的情况下,切断的所有边的最大花费的最小值(mid)

思路:最小化最大值,可以联系上二分答案, 那么就二分mid,dp[i]表示以i为根节点的子树,节点i和这颗子树所有叶子节点没有联系的最小花费,if(vis[v]) { if(w<=limit)dp[u]+=w;else dp[u]=1e6+1; }else {if(w<=limit)dp[u]+=min(dp[v],w);else dp[u]+=dp[v];}

vis[v]为1表示v为叶子节点,因为要断了和叶子节点的联系  当w>limit的时候 dp[u]要为1e6+1,为什么要为1e6+1呢,因为他没有断了和所有叶子节点 的联系并且 1e6+1>m(1e6)并且1e6*1e3在int范围内

树形背包题目

HDU 1561  The more, The Better

题意:有n个城市,每个城市有一定价值的宝物,要选m个城市,但是依赖条件选 x,必须要选y,求选m个城市的最大价值

思路:将0看成虚根节点,所有的依赖关系就是一颗树了,选子节点必须选父亲节点,每到一个节点,看成分组背包模型,每个儿子节点就是一组物品

POJ  1155 TELE

题意:有一颗n个节点的树,1为根节点,n-m+1到n为叶子节点求,每个叶子节点有一个权值,每条边有一个权值,要取一个叶子节点要花费 叶子节点的权值减去根到叶子节点的边权值和 重复路径只要减一次,求最多取的叶子节点数,并且能保证花费大于等于0

思路:假设叶子节点的权值为收入,dp[i][j]表示在节点i取j个叶子节点的最大收入,dp[i][j]=max(dp[i][j-k]+dp[son(i)][k]-w)

注意一个状态在一个儿子不能重复更新,注意for循环dp时的边界点;

POJ 1947  Rebuilding Roads

题意:有一颗n个节点的无根树,n-1条双向边,假设1为根节点,给一个p,断掉一些边,求剩下p个节点的子树最少要断多少条边;

思路:dp[i][j]表示以i为根节点的子树剩下j个节点需要断的最少边数,dp[i][1]=0,表示一个儿子节点边也不断,   然后我们对i的每个子节点进行分组背包,当在x这个儿子节点取的节点为0时,就dp[i][j]++,表示这条边要断,当在x这个儿子节点取的点不为0时

dp[i][j]=max(dp[i][j-k]+dp[x][k])

HDU  4003    Find Metal Mineral

题意:给你一颗有n个节点的树,给出每两个相连节点边的权值(如果你的一个机器人要走这条边花费的能量),再给你k个机器人,问从s点出发,最少花费多少能量可以遍历所有的节点。

思路:我们可以设立 dp 数组 dp[i][j] 表示节点 i 损失 j 个机器人遍历以节点 i 为根节点组成的子树的所有点所需的最小能量,因为我们要遍历所有的节点,所以节点i来说,我们要遍历它的所有的子节点,即它每个子节点的dp值我们都要取一个,因为是多组背包,为了保证每一组物品都至少取一个,所以我们的在执行递推之前先把当前子节点损失机器人数为0的先加到当前节点的花费里面(这就保证了每组至少取一个),它的状态转移方程就是dp[i][j] =dp[i][j] + dp[k][0]+ 2*f[i][k] ;其中 i 表示当前节点,j 代表当前节点损失的机器人数,k 表示当前节点的子节点,f[i][k] 表示i节点到 k 节点的花费,让我们再深入解析一下我们的dp数组, dp 数组 dp[i][j] 表示当前节点 i 花费它父节点j个机器人来遍历以 i 节点组成的子树的所有节点花费的最少能量(如果它花费 j=0 时表示它花费了父节点0个机器人遍历该子树所有的点所需的最少花费,不就是要回来吗,而那些损失数 j 大于零的,我就没必要遍历完子树的所有节点后再让它们回到 i 节点,因为没必要,会增加能量消耗,反正我要损失掉 i 父节点j 个机器人,它们都不回到 i 节点,不就相当于一开始我们说的 i 节点损失了 j 个机器人吗),这样就可以推出我们的dp方程 dp[i][j]+=max(dp[i][j],dp[i][j-l]+dp[k][l]+l*f[i][k]);为什么是加 l*f[i][k] 呢,看了上面的解释应该不难理解,就是先从 i 派出 l 个机器人到 k 所需的花费.

POJ 2486 Apple Tree

题意:给你一颗n个节点的树,每个节点有一个权值,让你从节点1开始走,走k步,每走到一个节点,价值加上那个节点的权值,

每个权值只可以加一次,求最大价值

思路:按照我们的惯性思维,dp[i][j]表示以i为根节点,走j步的最大价值,但是那么每到一个根节点就要分情况讨论是不是从这个儿子节点回来的,那么我们不妨用dp[i][j][0]表示不回到i节点,dp[i][j][1]表示回到i节点,那么很容易得到状态转移方程

 dp[u][j+2][1]=max(dp[u][j+2][1],dp[u][j-k][1]+dp[v][k][1]);                  
 dp[u][j+1][0]=max(dp[u][j+1][0],dp[u][j-k][1]+dp[v][k][0]);
 dp[u][j+2][0]=max(dp[u][j+2][0],dp[u][j-k][0]+dp[v][k][1]);

猜你喜欢

转载自blog.csdn.net/hutwuguangrong/article/details/89490064
今日推荐