题目

网上出现了一种高科技产品——人品测试器。只要你把你的真实姓名输入进去,系统将自动输出你的人品指数。把儿不相信自己的人品为0。经过了许多研究后,把儿得出了一个更为科学的人品计算方法。这种方法的理论依据是一个非常重要的结论:人品具有遗传性。因此,一个人的人品完全由他的祖先决定。把儿提出的人品计算方法相当简单,只需要将测试对象的k个祖先的人品指数(可能为负数)加起来即可。选择哪K个祖先可以由测试者自己决定,但必须要满足这个要求:如果除自己的父母之外的某个祖先被选了,那么他的下一代必需要选(不允许跳过某一代选择更远的祖先,否则将失去遗传的意义)。

非常不幸的是,把儿测试了若干次,他的人品值仍然不能为一个正数。现在把儿需要你帮助他找到选择祖先的最优方案,使得他的人品值最大。

输入格式:

数据的第一行是两个用空格隔开的正整数n和k,其中n代表把儿已知的家谱中共有多少人(包括把儿本身在内),k的意义参见问题描述。
数据的第二行有n-1个用空格隔开的整数(可能为负),这些数的绝对值在2^15以内。其中,第i个数表示编号为i+1的人的人品值。我们规定,编号为1的人是把儿。
接下来n行每行有两个用空格隔开的数,其中第i行的两个数分别表示第i个人的父亲和母亲的编号。如果某个人的父亲或母亲不在这个家谱内,则在表示他的父亲或母亲的编号时用0代替。
输入数据中除把儿以外的所有人都是把儿的祖先,他们都会在输入数据中作为父亲或母亲被描述到。输入数据中每个人都不可能同时作为多个人的父亲或者是母亲。

输出格式:

将把儿能够得到的最大人品值输出

样例输入:

  1. 6 3
  2. -2 3 -2 3 -1
  3. 2 3
  4. 4 5
  5. 0 6
  6. 0 0
  7. 0 0
  8. 0 0

样例输出:

  1. 4

数据范围:

对于50%的数据,n<=10;
对于100%的数据,n<=100。

时间限制:

1000

空间限制:

10240

做法:

ans[i][j]表示编号为i的人选j个祖先及自身的最大人品值
ans[i][j]=a[i]+max{ans[lc[i]][k]+ans[rc[i]][j-k-1]}
(0<=k<=j-1,num[lc[i]]>=k,num[rc[i]]>=j-k-1 --> k>=j-num[rc[i]]-1)
直接设定ans[0][0]=0即可,不用加特判

  1. #include<cstdio>
  2. #include<cstring>
  3. typedef long long LL;
  4. bool vis[];
  5. LL n,k;
  6. LL lc[],rc[],a[];
  7. LL dp[][];
  8. LL num[];//记录某结点及所有后代结点的总数量
  9. LL min(LL x,LL y)
  10. {
  11. return x>y?y:x;
  12. }
  13. LL max(LL x,LL y)
  14. {
  15. return x>y?x:y;
  16. }
  17. LL dfs(LL x)
  18. {
  19. num[x]=;
  20. if(lc[x]) num[x]+=dfs(lc[x]);
  21. if(rc[x]) num[x]+=dfs(rc[x]);
  22. return num[x];//改成这样提速效果不大
  23. }
  24. /*
  25. LL dfs(LL x)
  26. {
  27. if(x==0) return 0;
  28. num[x]=dfs(lc[x])+dfs(rc[x])+1;
  29. return num[x];
  30. }
  31. LL dp(LL i,LL j)
  32. {
  33. if(j==0) return 0;
  34. if(j==1) return a[i];
  35. LL k,ans1=-0x3f3f3f3f;
  36. for(k=max(j-num[rc[i]]-1,0);k<=min(num[lc[i]],j-1);k++)
  37. ans1=max(ans1,dp(lc[i],k)+dp(rc[i],j-k-1));
  38. return ans1+a[i];//这样写T两个点
  39. }//下面的貌似是类似常数优化的,不知道为什么差距这么大
  40. //理论上不用记忆化,毕竟这个树形结构没有重叠子问题,也许是减少了函数调用次数
  41. */
  42. void Dp(LL x)//直接处理完一个结点选任意数量子结点的答案
  43. //这样写全部0ms过
  44. {
  45. dp[x][]=a[x];
  46. dp[x][]=;
  47. if(lc[x]) Dp(lc[x]);
  48. if(rc[x]) Dp(rc[x]);
  49. int i,j;
  50. for(i=;i<=num[x];i++)
  51. {
  52. for(j=max(i-num[rc[x]]-,);j<=min(num[lc[x]],i-);j++)
  53. dp[x][i]=max(dp[x][i],dp[lc[x]][j]+dp[rc[x]][i-j-]);
  54. //傻了,曾经写成dp[x][i]=max(dp[lc[x]][j],dp[rc[x]][i-j-1]);了
  55. dp[x][i]+=a[x];//曾经忘记//曾经将a[x]写成a[i]
  56. }
  57. }
  58. /*
  59. void Dp(LL x)//直接处理完一个结点选任意数量子结点的答案
  60. //这样写也是全部0ms过
  61. {
  62. //dp[x][1]=a[x];
  63. dp[x][0]=0;
  64. if(lc[x]) Dp(lc[x]);
  65. if(rc[x]) Dp(rc[x]);
  66. int i,j;
  67. for(i=1;i<=num[x];i++)
  68. {
  69. for(j=max(i-num[rc[x]]-1,0);j<=min(num[lc[x]],i-1);j++)
  70. dp[x][i]=max(dp[x][i],dp[lc[x]][j]+dp[rc[x]][i-j-1]);
  71. dp[x][i]+=a[x];
  72. }
  73. }
  74. */
  75. int main()
  76. {
  77. LL i;
  78. memset(dp,,sizeof(dp));
  79. scanf("%lld%lld",&n,&k);
  80. for(i=;i<=n;i++)
  81. scanf("%lld",&a[i]);
  82. for(i=;i<=n;i++)
  83. scanf("%lld%lld",&lc[i],&rc[i]);
  84. dfs();
  85. //dp[0][1]=0;//不需要,因为num[0]=0,与0有关的最多只涉及到dp[0][0]
  86. dp[][]=;
  87. Dp();
  88. printf("%lld",dp[][k+]);//算上自己共要选k+1人
  89. return ;
  90. }

人品问题 树形dp的更多相关文章

  1. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  2. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  3. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  4. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  5. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  6. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  7. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

  8. hdu1561 The more, The Better (树形dp+背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...

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

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

随机推荐

  1. 图像处理之 opencv 学习---opencv 中的常用算法

    http://blog.csdn.net/lindazhou2005/article/details/1534234 文中有提到鲁棒性 http://blog.csdn.net/chary8088/a ...

  2. HTML——使用表格进行页面布局

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. id、NSObject *、id<NSObject>、instancetype

    1. id 与 NSObject * (1) id 是 Objective-C 对象,但是并不一定是NSObject对象,并非所有的Foundation/Cocoa对象都是继承于NSObject对象的 ...

  4. iOS UI控件之间的关系图

  5. G.易彰彪的一张表

    易彰彪最近有点奇怪,一向爱打游戏他最近居然盯着一张全是大小写字母的表在看,好像在找什么东西.他说,这是他女神给他的一张表,他需要回答女神的问题——在忽略大小写(即大写字母和小写字母视为同一字母)的情况 ...

  6. Hihocoder #1077 : RMQ问题再临-线段树(线段树:结构体建树+更新叶子往上+查询+巧妙使用father[]+线段树数组要开大4倍 *【模板】)

    #1077 : RMQ问题再临-线段树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到:小Hi给小Ho出了这样一道问题:假设整个货架上从左到右摆放了N种商品,并 ...

  7. YTU 2391: 求素数

    2391: 求素数 时间限制: 1 Sec  内存限制: 128 MB 提交: 116  解决: 3 题目描述 设计一个程序,输出所有小于等于n(n为一个大于2的正整数)的素数. 要求:(1)每行输出 ...

  8. [SHOI 2013] 发微博

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4419 [算法] 用std :: set维护每个人的好友集合 当两人成为好友时将每人接 ...

  9. 空间数据索引RTree完全解析及Java实现

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/MongChia1993/article/details/69941783 第一部分 空间数据的背景介 ...

  10. bzoj1911 [Apio2010]特别行动队——斜率优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1911 相当明显的斜率优化,很好做: 注意slp里面要有(double),以免出现精度问题. ...