http://acm.hdu.edu.cn/showproblem.php?pid=5834

题意:

一棵树上每个节点有一个价值$Vi$,每个节点只能获得一次,每走一次一条边要花费$Ci$,问从各个节点出发最多能收获多少价值。

思路:

需要考虑子节点和父亲节点两个方面。既然是这样,那就需要两次dfs来解决问题了,$dp[u][0]$表示从u出发最后还是回到u的最大价值和,$dp[u][1]$表示从u出发最后不回到u的最大价值和。

第一次dfs很显然就是计算出每个节点往其子树方向的$dp[u][0]$和$dp[u][1]$值。

第二次dfs就是再去考虑每个节点加上其父节点的情况,这里就需要维护一个最大值和一个次大值了,为什么呢?因为父节点的最大值可能最后停在了v子树,那么v子树到时候再去考虑父节点的时候就不对了,所以此时要将它改成次大值,这样它的最大值最后不会停在v子树。

总而言之,这是一道很经典的树形dp,不过没写出来。。

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<vector>
  6. #include<stack>
  7. #include<queue>
  8. #include<cmath>
  9. #include<map>
  10. #include<set>
  11. using namespace std;
  12. typedef long long ll;
  13. typedef pair<int,int> pll;
  14. const int INF = 0x3f3f3f3f;
  15. const int maxn=1e5+;
  16.  
  17. int n;
  18. int val[maxn];
  19. int dp[maxn][];
  20. vector<pll> G[maxn];
  21.  
  22. void dfs1(int u, int fa) //求出每个顶点往子树方向的最大值,dp[u][0]表示最终回到u,dp[u][1]表示最终不回到u
  23. {
  24. dp[u][]=dp[u][]=val[u];
  25. for(int i=;i<G[u].size();i++)
  26. {
  27. int v=G[u][i].first;
  28. int w=G[u][i].second;
  29. if(v==fa) continue;
  30. dfs1(v,u);
  31. if(dp[v][]-*w>) dp[u][]+=dp[v][]-*w;
  32. }
  33. for(int i=;i<G[u].size();i++)
  34. {
  35. int v=G[u][i].first;
  36. int w=G[u][i].second;
  37. if(v==fa) continue;
  38. int tmp = dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
  39. if(dp[u][]<tmp) dp[u][]=tmp;
  40. }
  41. }
  42.  
  43. void dfs2(int u, int fa, int cost) //处理往父亲节点的方向
  44. {
  45. int dir_tree=u;
  46. if(fa!=-) if(dp[fa][]-*cost>) dp[u][]+=dp[fa][]-*cost;
  47. int sub_large=dp[u][]=dp[u][];
  48. for(int i=;i<G[u].size();i++)
  49. {
  50. int v=G[u][i].first;
  51. int w=G[u][i].second;
  52. int tmp=dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
  53. if(tmp>=dp[u][]) //计算最大权值和次大权值
  54. {
  55. sub_large=dp[u][];
  56. dp[u][]=tmp;
  57. dir_tree=v;
  58. }
  59. else if(tmp>=sub_large) sub_large=tmp;
  60. }
  61. int pre0=dp[u][],pre1=dp[u][]; //出去该父节点对其子节点的影响
  62. for(int i=;i<G[u].size();i++)
  63. {
  64. int v=G[u][i].first;
  65. int w=G[u][i].second;
  66. if(v==fa) continue;
  67. int tmp=dp[v][]-*w;
  68. if(tmp>) dp[u][]-=tmp; //子节点v往父节点走时,肯定不会再算v节点的子树
  69. if(dir_tree==v) dp[u][]=sub_large; //如果u的最大值最后停留在v子树,则改成次大值
  70. if(tmp>) dp[u][]-=tmp; //和上面的第2句相同
  71. dfs2(v,u,w);
  72. dp[u][]=pre0,dp[u][]=pre1;
  73. }
  74.  
  75. }
  76.  
  77. int main()
  78. {
  79. //freopen("in.txt","r",stdin);
  80. int T;
  81. int kase=;
  82. scanf("%d",&T);
  83. while(T--)
  84. {
  85. scanf("%d",&n);
  86. for(int i=;i<=n;i++) {G[i].clear();scanf("%d",&val[i]);}
  87. for(int i=;i<n;i++)
  88. {
  89. int u,v,w;
  90. scanf("%d%d%d",&u,&v,&w);
  91. G[u].push_back(make_pair(v,w));
  92. G[v].push_back(make_pair(u,w));
  93. }
  94. printf("Case #%d:\n",++kase);
  95. dfs1(,-);
  96. dfs2(,-,);
  97. for(int i=;i<=n;i++) printf("%d\n",dp[i][]);
  98. }
  99. return ;
  100. }

HDU 5834 Magic boy Bi Luo with his excited tree(树形dp)的更多相关文章

  1. hdu 5834 Magic boy Bi Luo with his excited tree 树形dp+转移

    Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 13107 ...

  2. hdu-5834 Magic boy Bi Luo with his excited tree(树形dp)

    题目链接: Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: ...

  3. 【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边 ...

  4. 动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8UAAAJbCAIAAABCS6G8AAAgAElEQVR4nOy9fXQcxZ0uXH/hc8i5N+

  5. HDU 5834 Magic boy Bi Luo with his excited tree

    树形dp. 先dfs一次处理子树上的最优解,记录一下回到这个点和不回到这个点的最优解. 然后从上到下可以推出所有答案.细节较多,很容易写错. #pragma comment(linker, " ...

  6. HDU5834 Magic boy Bi Luo with his excited tree (树形DP)

    题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从i ...

  7. HDU5834Magic boy Bi Luo with his excited tree 树形dp

    分析:典型的两遍dfs树形dp,先统计到子树的,再统计从祖先来的,dp[i][0]代表从从子树回来的最大值,dp[i][1]代表不回来,id[i]记录从i开始到哪不回来 吐槽:赛场上想到了状态,但是不 ...

  8. 2016中国大学生程序设计竞赛 - 网络选拔赛 C. Magic boy Bi Luo with his excited tree

    Magic boy Bi Luo with his excited tree Problem Description Bi Luo is a magic boy, he also has a migi ...

  9. 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

    // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...

随机推荐

  1. 原生的强大DOM选择器querySelector - querySelector和querySelectorAll

    在传统的 JavaScript 开发中,查找 DOM 往往是开发人员遇到的第一个头疼的问题,原生的 JavaScript 所提供的 DOM 选择方法并不多,仅仅局限于通过 tag, name, id ...

  2. [py][mx]django静态文件目录配置

    使用TemplateView直接返回html from django.views.generic import TemplateView urlpatterns = [ path('',Templat ...

  3. PAT 1076 Forwards on Weibo[BFS][一般]

    1076 Forwards on Weibo (30)(30 分) Weibo is known as the Chinese version of Twitter. One user on Weib ...

  4. 机器学习理论基础学习3.3--- Linear classification 线性分类之logistic regression(基于经验风险最小化)

    一.逻辑回归是什么? 1.逻辑回归 逻辑回归假设数据服从伯努利分布,通过极大化似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的. logistic回归也称为逻辑回归,与线性回归这样输出 ...

  5. keras自定义padding大小

    1.keras卷积操作中border_mode的实现 def conv_output_length(input_length, filter_size, border_mode, stride): i ...

  6. NLP总览

    一.自然语言处理概述 1)自然语言处理:利用计算机为工具,对书面实行或者口头形式进行各种各样的处理和加工的技术,是研究人与人交际中以及人与计算机交际中的演员问题的一门学科,是人工智能的主要内容. 2) ...

  7. 使用Fiddler远程抓包

    Fiddler简介以及web抓包 一.Fiddler简介 简单来说,Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯.网上简介很多,我们不多说. 二 ...

  8. testNG入门详解

    TestNG 的注释: @DataProvider @ExpectedExceptions @Factory @Test @Parameters <suite name="Parame ...

  9. Qt setMargin()和setSpacing() 的含义

    mainLayout=newQVBoxLayout(this); mainLayout->setMargin(30); //表示控件与窗体的左右边距 mainLayout->setSpac ...

  10. 查看mysql主外键信息

    SELECT  *FROMinformation_schema.key_column_usage tWHERE t.constraint_schema = '库名称'AND t.constraint_ ...