学习博客:https://www.cnblogs.com/qq936584671/p/10274268.html

树的性质:n个点,n-1条边,任意两个点之间只存在一条路径,可以人为设置根节点,对于任意一个节点只存在至多一个父节点,其余为子节点。

记忆化树形dp模型较为抽象难以理解,以下通过由浅到深的方式解析树形dp以及树的性质。

树形dp求树的直径:(在一颗树里找到点X,Y,使得|XY|最大)

如图,我们令A为根节点,令dfs遍历顺序为ABDGHEFC。

在我们的dfs计算过程中,我们从下往上求解每一个节点,总的来说我们要求两个东西:

1、以每一个节点为根,所能到达的最长路径dp【u】

2、以每一个节点为根,它下面的的树的最长路径ans(其实就是找到 两个没有重复路径的子树,例如以B为根节点,会找到BDG+BE而不会找到BDG+BDH)

然后将子树中以子树根为起点所能到达的最长路径传给父节点,最后得出答案

具体看下面代码:

struct Node
{
int nex,val;
};
vector<Node>node[maxn];//node[u][i].nex代表该节点的子节点 node[u][i].val代表该节点与子节点之间路径的权值
void dfs(int u,int fa)//该节点和该节点的父亲
{
for(int i=;i<node[u].size();i++)
{
int v=node[u][i].nex;
if(v!=fa)//防止回到父节点
{
dfs(v,u);//
ans=max(ans,d[u]+d[v]+node[u][i].val);//这个必须在下面一步的前面
d[u]=max(d[u],d[v]+node[u][i].val);
}
}
}

理解了基本的树形dp之后,开始下面的练习:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4616

学习链接:https://www.cnblogs.com/zyb993963526/p/7223861.html

题目大意:在一颗有n(n<5e4)个节点的树中,每个节点有权值和是否有陷阱,你可以最多踏进c(c<=3)个陷阱,当你进入第c个陷阱时,你就无法继续移动了,你可以在任意节点出发,获取经过节点的权值(无法重复获取同一个节点),求能得到的最大权值和。

思路:

有点像树链剖分,对于一个以u为根的子树,因为每个顶点只能经过一次,那我们只能选择它的一个子树往下走。就像是把这棵树分成许多链,最后再连接起来。

这道题目麻烦的地方是陷阱的处理,用d【u】【j】【0/1】表示以u为根的某一子节点经过j个陷阱后到达u的最大权值和,0/1表示起点是否有陷阱。

假设当前到达u时经过了k个陷阱,分下面几种情况进行讨论:

①如果k==c,那么起点和终点至少有一个是陷阱(可能有些人会认为终点一定会是陷阱,这样是没错的,因为起点和终点时相对的,你也可以把起点看做终点)。

②如果k<c,那么起点和终点是否是陷阱是任意的,可以有也可以没有。

具体看代码:

#include<iostream>
#include<vector>
#include<math.h>
#include<string.h>
using namespace std;
const int maxn=+;
int n,c;
int ans;
vector<int>G[maxn];
int val[maxn],trap[maxn];//分别存储节点的值和是否有陷阱
int d[maxn][][];//d[u][j][0/1]表示以u为根的某一子节点经过j个陷阱之后到达u的最大权值和
void dfs(int u,int fa)
{
d[u][trap[u]][trap[u]]=val[u]; //计算以u为根的子树所能获得的最大值,也就是将子树的链进行连接
for(int i=;i<G[u].size();i++)
{
int v=G[u][i];
if(v!=fa)
{
dfs(v,u);
for(int j=;j<=c;j++)
{
for(int k=;j+k<=c;k++)
{
if(j!=c) ans=max(ans,d[u][j][]+d[v][k][]);
if(k!=c) ans=max(ans,d[u][j][]+d[v][k][]);
if(j+k<c) ans=max(ans,d[u][j][]+d[v][k][]);//起点和终点都可以为非陷阱
if(j+k<=c) ans=max(ans,d[u][j][]+d[v][k][]);//起点和终点都可以为陷阱 }
}
for(int j=;j+trap[u]<=c;j++)
{
d[u][j+trap[u]][]=max(d[u][j+trap[u]][],d[v][j][]+val[u]);
if(j!=)
{
d[u][j+trap[u]][]=max(d[u][j+trap[u]][],d[v][j][]+val[u]);
}
}
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>c;//n个节点 最多可以踩c个陷阱
for(int i=;i<n;i++) G[i].clear();
for(int i=;i<n;i++) cin>>val[i]>>trap[i];//输入值和是否有陷阱
for(int i=;i<n;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
ans=;
memset(d,,sizeof(d));
dfs(,-);
cout<<ans<<endl;
}
}

树形dp学习的更多相关文章

  1. 树形DP 学习笔记

    树形DP学习笔记 ps: 本文内容与蓝书一致 树的重心 概念: 一颗树中的一个节点其最大子树的节点树最小 解法:对与每个节点求他儿子的\(size\) ,上方子树的节点个数为\(n-size_u\) ...

  2. 树形$dp$学习笔记

    今天学习了树形\(dp\),一开始浏览各大\(blog\),发现都\(TM\)是题,连个入门的\(blog\)都没有,体验极差.所以我立志要写一篇可以让初学树形\(dp\)的童鞋快速入门. 树形\(d ...

  3. 树形DP学习笔记

    树形DP 入门模板题 poj P2342 大意就是一群职员之间有上下级关系,每个职员有一个快乐值,但是只有在他的直接上级不在场的情况下才会快乐.求举行一场聚会的快乐值之和的最大值. 求解 声明一个数组 ...

  4. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...

  5. 树形dp|无根树转有根树|2015年蓝桥杯生命之树

    2015年蓝桥杯第十题--生命之树(无根树dfs) ①暴力解法:枚举子集(选点) + dfs判断连通性(题目要求连通)满足上面两个条件下找出最大值权值和 ②dfs无根树转有根树,递归找最优 先学习无根 ...

  6. 树形DP入门学习

    这里是学习韦神的6道入门树形dp进行入门,本来应放在day12&&13里,但感觉这个应该单独放出来好点. 这里大部分题目都是参考的韦神的思想. A - Anniversary part ...

  7. [学习笔记]树形dp

    最近几天学了一下树形\(dp\) 其实早就学过了 来提高一下打开树形\(dp\)的姿势. 1.没有上司的晚会 我的人生第一道树形\(dp\),其实就是两种情况: \(dp[i][1]\)表示第i个人来 ...

  8. bzoj2500: 幸福的道路(树形dp+单调队列)

    好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1 ...

  9. 【BZOJ-1060】时态同步 树形DP (DFS爆搜)

    1060: [ZJOI2007]时态同步 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2101  Solved: 595[Submit][Statu ...

随机推荐

  1. Pig Latin程序设计1

    Pig是一个大规模数据分析平台.Pig的基础结构层包括一个产生MapReduce程序的编译器.在编译器中,大规模并行执行依据存在.Pig的语言包括一个叫Pig Latin的文本语言,此语言有如下特性: ...

  2. Integer类的parseInt和valueOf的区别

    我们平时应该都用过或者见过parseInt和valueOf这两个方法.一般我们是想把String类型的字符数字转成int类型.从这个功能层面来说,这两个方法都一样,都可以胜任这个功能. 但是,我们进入 ...

  3. c++中怎么实现Java中finally语句

    所有学习c++的书籍都明确提出了,不要使用goto, 以免造成程序流程的混乱,使理解和调试程序都产生困难. 但是我们遇到这样一个场景怎么办:就是不管程序执行成功与否,都要执行一些资源释放语句,相当ja ...

  4. MVC身份验证.MVC过滤器.MVC6关键字Task,Async.前端模拟表单验证,提交.自定义匿名集合.Edge导出到Excel.BootstrapTree树状菜单的全选和反选.bootstrap可搜索可多选可全选下拉框

    1.MVC身份验证. 有两种方式.一个是传统的所有控制器继承自定义Control,然后再里面用MVC的过滤器拦截.所以每次网站的后台被访问时.就会先走入拦截器.进行前端和后端的验证 一个是利用(MVC ...

  5. c#百分比计算

    //此方法得到的百分比后小数太多,不行double percent=Convert.ToDouble(2)/Convert.ToDouble(34); string result=(percent*1 ...

  6. Oracle中date转为timstam可以函数to_timestamp的方式来转化

    data 转为timstam可以函数to_timestamp的方式来转化 Select to_timestamp('2018-02-27 09:48:28','yyyy-mm-dd hh24:mi:s ...

  7. gRPC官方文档(异步基础: C++)

    文章来自gRPC 官方文档中文版 异步基础: C++ 本教程介绍如何使用 C++ 的 gRPC 异步/非阻塞 API 去实现简单的服务器和客户端.假设你已经熟悉实现同步 gRPC 代码,如gRPC 基 ...

  8. [SinGuLaRiTy] 数论题目复习

    [SinGuLaRiTy-1020] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. [CQBZOJ 1464] Hankson 题目描述 H ...

  9. CF1101C Division and Union 线段相交问题

    #include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #i ...

  10. 使用RestTemplate时报错java.lang.IllegalStateException: No instances available for 127.0.0.1

    我在RestTemplate的配置类里使用了 @LoadBalanced@Componentpublic class RestTemplateConfig { @Bean @LoadBalanced ...