这个题是POJ1849的加强版。

先说一个很重要的结论,下面两种方法都是从这个结论出发的。

一个人从起点遍历一颗树,如果最终要回到起点,走过的最小权值就是整棵树的权值的2倍

而且K个人的情况也是如此,大不了只有一个人走,其他K-1个人待着不动就行了。

而题目中说了这些人不比回到原点,所以就想办法考虑哪些多走的路程,最后用整棵树权值2倍减去就好了。

一、

多数人的做法是分组背包,推荐这篇博客。

里面的状态的定义并不复杂,和网上那些千篇一律的做法比,思路很新颖。

f(i, j)表示i为根的子树有j个机器人出发,遍历这棵子树可以少走多少路。

最终答案为sum - f(S, K)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7
 8 const int maxn = 10000 + 10;
 9 const int maxk = 12;
10
11 int n, s, k;
12
13 vector<int> G[maxn], C[maxn];
14
15 int f[maxn][maxk];
16
17 void DP(int u, int fa)
18 {
19     for(int i = 0; i < G[u].size(); i++)
20     {
21         int v = G[u][i], w = C[u][i];
22         if(v == fa) continue;
23         DP(v, u);
24         for(int i = k; i >= 1; i--)
25             for(int j = 1; j <= i; j++)
26                 f[u][i] = max(f[u][i], f[u][i-j] + f[v][j] + (2 - j) * w);
27     }
28 }
29
30 int main()
31 {
32     while(scanf("%d%d%d", &n, &s, &k) == 3)
33     {
34         for(int i = 1; i <= n; i++) { G[i].clear(); C[i].clear(); }
35
36         int sum = 0;
37         for(int i = 1; i < n; i++)
38         {
39             int u, v, w; scanf("%d%d%d", &u, &v, &w);
40             sum += w;
41             G[u].push_back(v); C[u].push_back(w);
42             G[v].push_back(u); C[v].push_back(w);
43         }
44         sum <<= 1;
45
46         memset(f, 0, sizeof(f));
47         DP(s, 0);
48         printf("%d\n", sum - f[s][k]);
49     }
50
51     return 0;
52 }

代码君

二、

这篇博客中

还有一种更为巧妙的做法,就是每次从起点出发找到一条最长的路径,记录下路径的长度,然后把这条路径上边的权值变为相反数。注意,已经变为负权的边就不再变回去了。

这样找K次最长的路径,然后加起来就是可以最多少走多少路。

为什么要把权值变成负的,因为你第二次第三次再走这条路的时候,就表示少走了负的权值,也就是多走了。如果出现所有的路都是负权的情况,那么树中最长路的路径就是0,也就是机器人原地不动。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <vector>
 6 using namespace std;
 7
 8 const int maxn = 10000 + 10;
 9
10 struct Edge
11 {
12     int u, v, w;
13     Edge(int u, int v, int w):u(u), v(v), w(w) {}
14 };
15
16 vector<Edge> edges;
17 vector<int> G[maxn];
18
19 void AddEdge(int u, int v, int w)
20 {
21     edges.push_back(Edge(u, v, w));
22     edges.push_back(Edge(v, u, w));
23     int m = edges.size();
24     G[u].push_back(m - 2);
25     G[v].push_back(m - 1);
26 }
27
28 int n, s, k;
29
30 int len, id;
31 int pre[maxn];
32
33 void dfs(int u, int fa, int d)
34 {
35     if(d > len) { len = d; id = u; }
36     for(int i = 0; i < G[u].size(); i++)
37     {
38         Edge& e = edges[G[u][i]];
39         int v = e.v;
40         if(v == fa) continue;
41         pre[v] = G[u][i];
42         dfs(v, u, d + e.w);
43     }
44 }
45
46 int main()
47 {
48     while(scanf("%d%d%d", &n, &s, &k) == 3)
49     {
50         edges.clear();
51         int tot = 0;
52         for(int i = 1; i <= n; i++) G[i].clear();
53         for(int i = 1; i < n; i++)
54         {
55             int u, v, w; scanf("%d%d%d", &u, &v, &w);
56             tot += w;
57             AddEdge(u, v, w);
58         }
59         tot <<= 1;
60
61         int ans = 0;
62         for(int i = 0; i < k; i++)
63         {
64             len = 0, id = s;
65             pre[s] = -1;
66             dfs(s, 0, 0);
67             if(id == s) continue;
68             ans += len;
69             for(int u = id; u != s; u = edges[pre[u]].u)
70             {
71                 int& w = edges[pre[u]].w;
72                 if(w > 0) w = -w;
73             }
74         }
75
76         printf("%d\n", tot - ans);
77     }
78
79     return 0;
80 }

代码君

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4691931.html

HDU 4003 Find Metal Mineral相关推荐

  1. HDOJ 4003 Find Metal Mineral (树DP)

    题意:给定一棵树,边权表示通过此边的代价,给k个机器人,指定从点s出发,求遍历所有结点的最小代价和. 分析:设计状态时不难想到用dp[i][j]表示从结点 i 出发遍历以它为根的子树的最小代价,但是转 ...

  2. 有趣题目和认知合集(持续更新)

    写写对一些算法的理解,挂几个有意思的题,可能也会挂几个板子题 算法理解偏向于能懂即可,没有严格的证明 快乐几何 [1.2]Volatile Kite 点到直线 快乐搜与暴力 [2.4]Short Co ...

  3. NFPA-持续为美国贡献防火国家规范的非政府协会

    第一 首先介绍一下NFPA70(也就是常说的NEC)和NFPA的关系 The National Electrical Code (NEC), or NFPA 70, is a regionally a ...

  4. 对应的cuda版本 显卡驱动版本_cuda和显卡驱动版本

    Oracle 列数据聚合方法汇总 网上流传众多列数据聚合方法,现将各方法整理汇总,以做备忘. wm_concat 该方法来自wmsys下的wm_concat函数,属于Oracle内部函数,返回值类型v ...

  5. 树形DP --算法竞赛专题解析(17)

    本系列文章将于2021年整理出版,书名<算法竞赛专题解析>. 前驱教材:<算法竞赛入门到进阶> 清华大学出版社 网购:京东 当当      想要一本作者签名书?点我 如有建议, ...

  6. hdu 逃生_从办公室逃生(Python简介)

    hdu 逃生 Prerequisites: Have some way of coding in Python. If you don't have Python installed, I'd rec ...

  7. HDU——1106排序(istringstream的使用、STLvector练习)

    排序 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  8. hdu 5438 Ponds 拓扑排序

    Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem ...

  9. HDU 1248 寒冰王座(全然背包:入门题)

    HDU 1248 寒冰王座(全然背包:入门题) http://acm.hdu.edu.cn/showproblem.php?pid=1248 题意: 不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票 ...

最新文章

  1. spark 1.5.2配置记录
  2. java 怎么向串口发送指令_idea ssm项目java程序使用十六进制rxtx包向串口发送指令的方法...
  3. @TableLogic注解表示逻辑删除
  4. matlab中二维插值函数interp2的使用
  5. Windows驱动程序调用约定
  6. php页面的特点_带你认识PHP的四大特性八大优势
  7. MariaDB 10.0.X中,动态列支持 JSON 格式来获取数据
  8. webservice测试工具
  9. Windows 10 下使用 telnet 客户端/服务端工具进行连接
  10. 微信小程序下拉刷新简单
  11. 视频捕获增加color space converter + Transform Filter
  12. 《人生七年》纪录片-个体心理学中的自卑与超越角度解读
  13. 【考研英语-基础-长难句分析】特殊结构_分裂结构【插入式_同位语 插入语 状从 非限定从-从句后移式】
  14. Java毕业设计-社区疫情管理小程序
  15. html 键盘按键与按钮功能关联
  16. stm32f407能跑linux吗_stm32能跑linux吗
  17. 域名解析不生效,提示“未使用阿里云解析”如何解决?
  18. windows11/windows10设置移动热点自启(图文步骤教程)
  19. 基于vue2+element+springboot+mybatis+jpa+mysql的学籍管理系统
  20. Google招聘广告短片的启示

热门文章

  1. java三种注释_Java中三种常见的注释(注解) Annotation
  2. 笔记+R︱信用风险建模中神经网络激活函数与感知器简述
  3. Angular学习笔记(五) - 自定义表单控件
  4. React Native在Android当中实践(一)——背景介绍
  5. Oracle备份数据库
  6. cordova构建项目命令小结
  7. 更改Tomcat默认目录+端口+设置缺省网页的方法
  8. 你的公司有如下的症状吗?
  9. Internet Explorer 7 功能
  10. MySQL 死锁专题问题处理