题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的。问遍历完所有点的最小花费?

思路:

  非常经典,首先需要知道一点,才能往下推理。就是“如果在t点派c个机器人往孩子u,那么最多只有1个机器人能走会回来到t,否则花费总是不划算的”。

  稍微证明一下:

  (1)假设派1个机器人往u,逛一圈回到u的父亲t,花费v= 子树u的边权和*2 + e(t,u)*2。若机器人不要了,那花费肯定比v还要少。

  (2)假设派2个机器人往u,若要2个机器人都回来,显然花费要比(1)要大。若仅要1个机器人回来,花费仍比“仅派1只机器人往u”要高。(可以试试画一棵有3层的树,头两层只有1个节点,第三层节点数随意即可,来模拟一下就知道结果了)

  得到的结论是,要么只派c个机器人去孩子u,且1个都不要走回来(注:0<c<=k);要么派1个机器人出去,且遍历完子树u走回t。

  这样已经很好解决了。枚举下点t的孩子数(组),再枚举点t可能获得的机器人数(容量),再枚举给这个孩子派的机器人数(物品)。

  还有个初始化DP值的问题,因为每个孩子都是必须遍历的,而常规的分组背包是可选(至多选1件)或者不选物品的,那么可以先将“派1个机器人且回收1个机器人的DP值”丢进背包(保证了此容量下肯定有遍历过子树u),然后若有更好的状态再更新掉此容量。

  用DP[t][0]表示“有1个机器人到达t遍历完子树再走回t”的花费。DP[t][i]表示“有i个机器人到达t且遍历完整棵子树t,且不要求回到t”的最小花费。

  1. #include <bits/stdc++.h>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <map>
  5. #include <vector>
  6. #include <iostream>
  7. #define pii pair<int,int>
  8. #define INF 0x3f3f3f3f
  9. #define LL long long
  10. using namespace std;
  11. const int N=;
  12. struct tower
  13. {
  14. int pri,pow;
  15. }tow[N][];
  16.  
  17. struct node
  18. {
  19. int from,to,next;
  20. node(){};
  21. node(int from,int to,int next):from(from),to(to),next(next){};
  22. }edge[N*];
  23.  
  24. int edge_cnt, head[N], cnt[N], dp[N][], n, m ;
  25. void add_node(int from,int to)
  26. {
  27. edge[edge_cnt]=node(from, to, head[from]);
  28. head[from]=edge_cnt++;
  29. }
  30. inline int cmp(tower a,tower b){return a.pri<b.pri;}
  31.  
  32. void DFS(int t,int far)
  33. {
  34. node e;
  35. int flag=;
  36. for(int i=head[t]; i!=-; i=e.next)
  37. {
  38. e=edge[i];
  39. if(e.to==far) continue;
  40. DFS(e.to, t);
  41.  
  42. for(int j=m; j>=; j-- ) //容量
  43. {
  44. dp[t][j]=min(dp[t][j], dp[e.to][]); //先装代价为0的,如果有更好的再代替掉。
  45. for(int k=; k<=j; k++ ) //给此孩子k元,得到的最大攻击力。
  46. dp[t][j]=max(dp[t][j], min(dp[t][j-k], dp[e.to][k]));
  47. }
  48. flag=; //标记是否叶子。
  49. }
  50. if(flag==) memset(dp[t], , sizeof(dp[t])); //叶子节点
  51.  
  52. //本节点的决策是“仅有1组的分组背包”模型: 必须且最多买1个。(不买就只能靠孩子来防御)
  53. for(int j=m; j>=; j-- ) //容量
  54. {
  55. int k=;
  56. for( ; k<cnt[t] && !tow[t][k].pri; k++ ) //不用钱的,只留1个power最大的.
  57. if(tow[t][k-].pow > tow[t][k].pow)
  58. swap(tow[t][k],tow[t][k-]);
  59.  
  60. for( k-- ; k<cnt[t]; k++) //物品
  61. {
  62. if(j-tow[t][k].pri>=)
  63. dp[t][j]=max(dp[t][j], dp[t][j-tow[t][k].pri] + tow[t][k].pow ); //可以直接挡
  64. }
  65. }
  66. }
  67.  
  68. int main()
  69. {
  70. freopen("input.txt", "r", stdin);
  71. int t, a, b; cin>>t;
  72. while(t--)
  73. {
  74. edge_cnt=;
  75. memset(head, -, sizeof(head));
  76. memset(dp, 0x3f, sizeof(dp)); //注意初始化
  77.  
  78. scanf("%d",&n);
  79. for(int i=; i<n; i++) //无向图
  80. {
  81. scanf("%d%d",&a,&b);
  82. add_node(a,b);
  83. add_node(b,a);
  84. }
  85.  
  86. scanf("%d",&m); //钱。
  87. for(int i=; i<=n; i++)
  88. {
  89. scanf("%d",&cnt[i]);
  90. for(int j=; j<cnt[i]; j++)
  91. scanf("%d%d", &tow[i][j].pri, &tow[i][j].pow);
  92. sort(tow[i], tow[i]+cnt[i], cmp); //免费的排前面
  93. }
  94. DFS(, -);
  95. printf("%d\n",dp[][m]);
  96. }
  97. return ;
  98. }

AC代码

HDU 4003 Find Metal Mineral (树形DP,经典)的更多相关文章

  1. hdu 4003 Find Metal Mineral 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...

  2. hdu 4003 Find Metal Mineral 树形dp ,*****

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  3. HDU 4003 Find Metal Mineral(分组背包+树形DP)

    题目链接 很棒的一个树形DP.学的太渣了. #include <cstdio> #include <string> #include <cstring> #incl ...

  4. HDU4003Find Metal Mineral[树形DP 分组背包]

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  5. HDU4003 Find Metal Mineral 树形DP

    Find Metal Mineral Problem Description Humans have discovered a kind of new metal mineral on Mars wh ...

  6. HDU-4003 Find Metal Mineral 树形DP (好题)

    题意:给出n个点的一棵树,有k个机器人,机器人从根节点rt出发,问访问完整棵树(每个点至少访问一次)的最小代价(即所有机器人路程总和),机器人可以在任何点停下. 解法:这道题还是比较明显的能看出来是树 ...

  7. hdu4003Find Metal Mineral(树形DP)

    4003 思维啊 dp[i][j]表示当前I节点停留了j个机器人 那么它与父亲的关系就有了 那条边就走了j遍 dp[i][j] = min(dp[i][j],dp[child][g]+dp[i][j- ...

  8. HDU 4003 Find Metal Mineral

    这个题是POJ1849的加强版. 先说一个很重要的结论,下面两种方法都是从这个结论出发的. 一个人从起点遍历一颗树,如果最终要回到起点,走过的最小权值就是整棵树的权值的2倍. 而且K个人的情况也是如此 ...

  9. hdu 4514 并查集+树形dp

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

随机推荐

  1. 华为CodeCraft2018 周进展

    上周: python验证lstm,效果不好.很多拟合的是直线.C++抄了个lstm,输出也是直线,不知道是程序的问题,还是模型的问题. 尝试bp神经网络求解.代码是抄的.回看天数是写死的,隐层只有一层 ...

  2. Eigen::aligned_allocator

    http://blog.csdn.net/rs_huangzs/article/details/50574141

  3. mysql创建用户及授权

    创建本地账号 create user 'egon1'@'localhost' identified by '123'; # mysql -uegon1 -p123 创建远程账号 create user ...

  4. Multipath TCP on iOS11 : A closer look at the TCP Options(转)

    Multipath TCP uses a variety of TCP options to use different paths simultaneously. Several Multipath ...

  5. E20181030-hm

    conquer  vt. 征服; 克服; 攻克; 打败(敌人);  vi. 得胜,胜利; recur vi. 复发; 重现; 再发生; 回想; recurrence n. 复回,重现; 反复,隐现; ...

  6. unity3d easytouch教程

    http://www.taikr.com/group/6/thread/1987 说一说easytouch的简单使用方法,和移动平台上的rpg游戏一样,我们肯定也不陌生,我们经常玩游戏的时候用的都是虚 ...

  7. [Xcode 实际操作]九、实用进阶-(16)给图片添加水印效果

    目录:[Swift]Xcode实际操作 本文将演示如何截取屏幕画面,并将截取图片,存入系统相册. 在项目文件夹[DemoApp]上点击鼠标右键 ->[New File]创建一个扩展文件-> ...

  8. Mol Cell Proteomics. |陈洁| 整合鸟枪法蛋白质组学中鉴定和定量的错误率

    大家好,本周分享的是发表在MCP上的一篇关于鸟枪蛋白质组学中的错误率的文章,题目是Integrated identification and quantification error probabil ...

  9. 自定义socket 模拟B/S服务端

    目录 通过什么实现连接? B/S 客户端与服务端交互过程 socket server端 python代码 (静态html反馈) socket server端 python代码 (动态html反馈) 小 ...

  10. 考虑实现Comparable接口

    考虑实现Comparable接口   compareTo方法没有在Object中声明.相反,它是Comparable接口中唯一的方法.compareTo方法不但允许进行简单的等同性比较,而且允许执行顺 ...