以为很水的一道题,花了大半天的时间才搞定,比赛的时候卡在这题上了,伤不起啊。。。

题意:给一棵树,每个结点中有礼物,每个礼物有一个权值,某些结点中会有陷阱,你可以从任何一点出发,每个结点最多只能经过一次,最多掉进陷阱C次,求出可获得的礼物的最大值。

思路:典型的树形DP   ,状态可用dp[x][y][z]来表示,x代表以x为根结点的子树,y代表恰好经过了几个陷阱,z代表方向(0,1),表示从此子树进来或是出去。

dp[x][y][0]的含义是从子树x中出来,恰好经过y个陷阱所能获得的最大礼物值,dp[x][y][1]的含义是进入子树x,恰好经过y个陷阱所能获得的最大礼物值。

状态转移方程:

如果结点x有陷阱:dp[x][y][z]=max(dp[u][y-1][z])

如果结点x无陷阱:dp[x][y][z]=max(dp[u][y][z]),u是x的子结点

先把无根树转化为有根树,用一个全局变量记录答案,每求出一棵子树的dp值,就把答案更新一次:一种找出该子树中两棵不同的子子树,一颗出树,一颗入树,在两树通过父结点x连到一起,在该路径上的陷阱数不超过C的情况下,通过枚举两棵子子树上的陷阱数来更新答案,另一种是找出一棵子子树上的单条路径,在陷阱数不超过C的情况下,更新答案。

一定要注意该子树根结点有陷阱和无陷阱时要分开处理。

整体采用记忆化搜索实现。

细节太多,不再一一叙述,详情见代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
vector<int>v[50005];
int N,C,b[50005],r[50005];
LL a[50005],res,dp[50005][4][2];
bool vis[50005][4][2];
void root(int x)
{for (int i=0; i<v[x].size(); ++i)if (v[x][i]!=r[x]){r[v[x][i]]=x;root(v[x][i]);}
}LL dfs(int x,int y,int z);void update(int x)
{vector<LL>ls[4],rs[4],e[4];if (v[x].size()==1 && x){if (!b[x]) res=max(res,a[x]);else if (C) res=max(res,a[x]);}else if ((!x && v[x].size()==1) || (x && v[x].size()==2))return;else if (!b[x]){for (int j=0; j<4; ++j)for (int i=0; i<v[x].size(); ++i)if (v[x][i]!=r[x]){if (dfs(v[x][i],j,0)){ls[j].push_back(dfs(v[x][i],j,0)+a[x]);rs[j].push_back(dfs(v[x][i],j,0)+a[x]);}else{ls[j].push_back(dfs(v[x][i],j,0));rs[j].push_back(dfs(v[x][i],j,0));}if (dfs(v[x][i],j,1))e[j].push_back(dfs(v[x][i],j,1)+a[x]);elsee[j].push_back(dfs(v[x][i],j,1));}for (int j=0; j<4; ++j){LL now=ls[j][0];for (int i=1; i<ls[j].size(); ++i)if (ls[j][i]){if (ls[j][i]>now) now=ls[j][i];else ls[j][i]=now;}now=rs[j][rs[j].size()-1];for (int i=ls[j].size()-2; i>=0; --i)if (rs[j][i]){if (rs[j][i]>now) now=rs[j][i];else rs[j][i]=now;}}for (int i=0; i<=C; ++i)for (int k=0; k<e[i].size(); ++k)for (int j=0; j<=C-i; ++j)if (e[i][k] && ((k && ls[j][k-1]) || (k<rs[j].size()-1 && rs[j][k+1]))){if (C && j==C) continue;LL u=0;if (k) u=max(u,ls[j][k-1]);if (k<rs[j].size()-1) u=max(u,rs[j][k+1]);res=max(res,u+e[i][k]-a[x]);}}else{for (int j=0; j<4; ++j)for (int i=0; i<v[x].size(); ++i)if (v[x][i]!=r[x]){if (dfs(v[x][i],j,0)){ls[j].push_back(dfs(v[x][i],j,0)+a[x]);rs[j].push_back(dfs(v[x][i],j,0)+a[x]);}else{ls[j].push_back(dfs(v[x][i],j,0));rs[j].push_back(dfs(v[x][i],j,0));}if (dfs(v[x][i],j,1))e[j].push_back(dfs(v[x][i],j,1)+a[x]);elsee[j].push_back(dfs(v[x][i],j,1));}for (int j=0; j<4; ++j){LL now=ls[j][0];for (int i=1; i<ls[j].size(); ++i)if (ls[j][i]){if (ls[j][i]>now) now=ls[j][i];else ls[j][i]=now;}now=rs[j][rs[j].size()-1];for (int i=ls[j].size()-2; i>=0; --i)if (rs[j][i]){if (rs[j][i]>now) now=rs[j][i];else rs[j][i]=now;}}for (int i=0; i<C; ++i)for (int k=0; k<e[i].size(); ++k)for (int j=0; j<=C-i-1; ++j)if (e[i][k] && ((k && ls[j][k-1]) || (k<rs[j].size()-1 && rs[j][k+1]))){if (j==C-1) continue;LL u=0;if (k) u=max(u,ls[j][k-1]);if (k<rs[j].size()-1) u=max(u,rs[j][k+1]);res=max(res,u+e[i][k]-a[x]);}}
}int main()
{int T;
//    freopen("1006.in","r",stdin);
//    freopen("out.txt","w",stdout);scanf("%d",&T);while (T--){int x,y;scanf("%d%d",&N,&C);for (int i=0; i<N; ++i) scanf("%I64d%d",&a[i],&b[i]);for (int i=0; i<N; ++i) v[i].clear();for (int i=1; i<N; ++i){scanf("%d%d",&x,&y);v[x].push_back(y);v[y].push_back(x);}r[0]=-1;root(0);res=0;memset(vis,0,sizeof(vis));dfs(0,0,0);/*for (int i=0; i<N; ++i)for (int j=0; j<4; ++j)for (int k=0; k<2; ++k)printf("dp[%d][%d][%d]=%lld\n",i,j,k,dp[i][j][k]);*/printf("%I64d\n",res);}return 0;
}LL dfs(int x,int y,int z)
{if (vis[x][y][z]) return dp[x][y][z];for (int i=0; i<4; ++i)for (int j=0; j<2; ++j){vis[x][i][j]=true;dp[x][i][j]=0;}if (v[x].size()==1 && x){if (!b[x])dp[x][0][0]=dp[x][0][1]=a[x];elsedp[x][1][0]=dp[x][1][1]=a[x];}else if (!b[x]){for (int i=0; i<v[x].size(); ++i)if (v[x][i]!=r[x])for (int j=0; j<4; ++j){dp[x][j][0]=max(dp[x][j][0],dfs(v[x][i],j,0));dp[x][j][1]=max(dp[x][j][1],dfs(v[x][i],j,1));}for (int i=0; i<4; ++i)for (int j=0; j<2; ++j)if (dp[x][i][j])dp[x][i][j]+=a[x];}else{for (int i=0; i<v[x].size(); ++i)if (v[x][i]!=r[x])for (int j=1; j<4; ++j){dp[x][j][0]=max(dp[x][j][0],dfs(v[x][i],j-1,0));dp[x][j][1]=max(dp[x][j][1],dfs(v[x][i],j-1,1));}for (int i=1; i<4; ++i)for (int j=0; j<2; ++j)if (dp[x][i][j])dp[x][i][j]+=a[x];dp[x][1][1]=a[x];if (!dp[x][1][0]) dp[x][1][0]=a[x];}update(x);if (!b[x]){for (int i=0; i<C; ++i)res=max(res,dp[x][i][0]);for (int i=0;i<=C;++i)res=max(res,dp[x][i][1]);}else{for (int i=1;i<=C;++i)res=max(res,dp[x][i][0]);for (int i=1;i<=C;++i)res=max(res,dp[x][i][1]);}return dp[x][y][z];
}

  

转载于:https://www.cnblogs.com/Chierush/p/3217992.html

hdu4616_Game_树形DP相关推荐

  1. BNUOJ 52305 Around the World 树形dp

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

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

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

  3. fwt优化+树形DP HDU 5909

    1 //fwt优化+树形DP HDU 5909 2 //见官方题解 3 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ 4 5 #include ...

  4. BZOJ 1040 ZJOI2008 骑士 树形DP

    题目大意:给定一个基环树林,每一个点上有权值,要求选择一个权值和最大的点集,要求点集中的随意两个点之间不能直接相连 最大点独立集--考虑到n<=100W,网络流铁定跑不了,于是我们考虑树形DP ...

  5. POJ 3342 树形DP+Hash

    这是很久很久以前做的一道题,可惜当时WA了一页以后放弃了. 今天我又重新捡了起来.(哈哈1A了) 题意: 没有上司的舞会+判重 思路: hash一下+树形DP 题目中给的人名hash到数字,再进行运算 ...

  6. [NC15748]旅游 树形dp基础

    菜鸡第一次接触树形dp这个东西,不过这个东西还是很好理解的(可能是因为模板题吧) 个人感觉,相比线性dp,树形dp的状态转移方程更加的直观,难点主要是在"树"的结构上比较麻烦. 题 ...

  7. 容斥 + 树形dp ---- 2021 icpc 沈阳 L Perfect Matchings

    题目链接 题目大意: 就是给你一个2n2n2n个点的完全图,从这个图里面抽出2n−12n-12n−1条边,这些边形成一颗树,现在问你剩下的图里面点进行完美匹配有多少种方案? 解题思路: 一开始被完美匹 ...

  8. 树形dp ---- gym101667 A(贪心 + 树形dp + 两个dp方程组维护)

    题目链接 题目大意: 就是一棵5e35e35e3的树,可以选择一些点,放上基站,如果uuu上的基站价值为ddd,那么距离uuu小于等于ddd的点都会被覆盖,问使得整棵树被覆盖需要的最小价值. 解题思路 ...

  9. 树形dp ---- 2018年杭电多校第二场 H travel

    题目大意: 就是给你一个带点权的树,找到3条独立互不相交的路径使得权值和最大 解题思路: 很经典的树形dp 我们设dp[root][j][k]dp[root][j][k]dp[root][j][k]表 ...

最新文章

  1. 近乎于“神”的任正非
  2. Linux环境下段错误的产生原因及调试方法小结
  3. [转载] 中华典故故事(孙刚)——07 二百五
  4. MySQL—函数的使用
  5. java 基础面试 英文_[Java面试] 面试java基础总结大全
  6. java计算混淆矩阵(分类指标:查准率P,查全率R,P和R的调和均值F1,正确率A)
  7. 在Eclipse里搭建Go开发的环境
  8. 为什么PostgreSQL是最先进的开源数据库
  9. 手把手教你使用 VuePress 搭建个人博客
  10. 用计算机乘九位数怎么用,用计算器计算
  11. ubuntu删除OpenCV
  12. 2000w mysql_MySQL数据库优化(基于酒店2000w条数据)
  13. Android中Xposed框架篇---修改系统位置信息实现自身隐藏功能
  14. 爱帮网“搜索+社区”就地展开
  15. 新年新气象,专注于重要的事
  16. Accton Technology and Wedge Networks Partnership Launches Orchestrated Secure SD-WAN
  17. BZOJ 2708 木偶
  18. 数据结构 严薇敏 顺序表的实现(增 删 改)及其使用方法详解
  19. 开源项目CIIP(企业信息管理系统框架).2018.1.0910版更新介绍-上周工作总结
  20. mysql用了索引为什么还是查询很慢?

热门文章

  1. 【学习笔记】RecyclerView的使用
  2. [Twisted] Protocols协议和Protocol Factories 协议工厂
  3. 一杯“咸水”的人生哲理
  4. directx修复工具win7_win7提示explorer.exe应用程序错误的解决方法
  5. java(17) - 增强for循环、装箱拆箱、可变参数
  6. Andriod编程之Environment类
  7. 如何使用Android系统属性(SystemProperties)
  8. 【运维安全】-MySQL手工注入
  9. Mac node js环境的安装与测试
  10. go语言net包rpc远程调用的使用