这个题是POJ1849的加强版。

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

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

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

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

一、

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

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

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

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

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std; const int maxn = + ;
const int maxk = ; int n, s, k; vector<int> G[maxn], C[maxn]; int f[maxn][maxk]; void DP(int u, int fa)
{
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i], w = C[u][i];
if(v == fa) continue;
DP(v, u);
for(int i = k; i >= ; i--)
for(int j = ; j <= i; j++)
f[u][i] = max(f[u][i], f[u][i-j] + f[v][j] + ( - j) * w);
}
} int main()
{
while(scanf("%d%d%d", &n, &s, &k) == )
{
for(int i = ; i <= n; i++) { G[i].clear(); C[i].clear(); } int sum = ;
for(int i = ; i < n; i++)
{
int u, v, w; scanf("%d%d%d", &u, &v, &w);
sum += w;
G[u].push_back(v); C[u].push_back(w);
G[v].push_back(u); C[v].push_back(w);
}
sum <<= ; memset(f, , sizeof(f));
DP(s, );
printf("%d\n", sum - f[s][k]);
} return ;
}

代码君

二、

这篇博客中

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

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

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

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std; const int maxn = + ; struct Edge
{
int u, v, w;
Edge(int u, int v, int w):u(u), v(v), w(w) {}
}; vector<Edge> edges;
vector<int> G[maxn]; void AddEdge(int u, int v, int w)
{
edges.push_back(Edge(u, v, w));
edges.push_back(Edge(v, u, w));
int m = edges.size();
G[u].push_back(m - );
G[v].push_back(m - );
} int n, s, k; int len, id;
int pre[maxn]; void dfs(int u, int fa, int d)
{
if(d > len) { len = d; id = u; }
for(int i = ; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
int v = e.v;
if(v == fa) continue;
pre[v] = G[u][i];
dfs(v, u, d + e.w);
}
} int main()
{
while(scanf("%d%d%d", &n, &s, &k) == )
{
edges.clear();
int tot = ;
for(int i = ; i <= n; i++) G[i].clear();
for(int i = ; i < n; i++)
{
int u, v, w; scanf("%d%d%d", &u, &v, &w);
tot += w;
AddEdge(u, v, w);
}
tot <<= ; int ans = ;
for(int i = ; i < k; i++)
{
len = , id = s;
pre[s] = -;
dfs(s, , );
if(id == s) continue;
ans += len;
for(int u = id; u != s; u = edges[pre[u]].u)
{
int& w = edges[pre[u]].w;
if(w > ) w = -w;
}
} printf("%d\n", tot - ans);
} return ;
}

代码君

HDU 4003 Find Metal Mineral的更多相关文章

  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. HDU 4003 Find Metal Mineral (树形DP,经典)

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

  5. HDOJ 4003 Find Metal Mineral

    题意: 一棵有权树,从根结点中放入 K 个机器人.求用这 K 个机器人遍历全部的结点最少的权值和. 思路: 1. dp[u][i] 表示给以 u 为根节点的子树放 i 个机器人,遍历其子树所须要的最小 ...

  6. xtu summer individual 6 E - Find Metal Mineral

    Find Metal Mineral Time Limit: 1000ms Memory Limit: 65768KB This problem will be judged on HDU. Orig ...

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

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

  8. HDU 4003 (树形DP+背包)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4003 题目大意:有K个机器人,走完树上的全部路径,每条路径有个消费.对于一个点,机器人可以出去再回来 ...

  9. HDU4003 Find Metal Mineral 树形DP

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

随机推荐

  1. Spark Mllib里如何将trainDara训练数据文件里提取第M到第N字段(图文详解)

    不多说,直接上干货! 具体,见 Hadoop+Spark大数据巨量分析与机器学习整合开发实战的第13章 使用决策树二元分类算法来预测分类StumbleUpon数据集

  2. Java面试:投行的15个多线程和并发面试题(转)

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...

  3. vue+webpack+VS Code入门简单的项目配置

    为了方便,这边的编译器选择的是VS Code (Visual Studio Code); 打开VS Code,选择好自己的工作空间,然后新建一个文件夹作为我们项目的文件夹,然后,show time: ...

  4. Android 面试总结~~~

    一.面试中的问题 通过这几天的面试,总结了自己在面试过程中问到的问题,部分问题已经给出了答案,还有部分问题,还未有时间整理出来. ListView出现闪图.图片错乱原因解决方案 函数式编程 (Lamb ...

  5. 【Web应用-迁移】迁移 Web 应用到新的应用服务计划的相关限制和说明

    现象描述 当前 Web 应用所在的应用服务计划和目标应用服务计划属于同一个资源组,但是通过 Portal 点击 “更改应用服务计划”,依旧看不到目标应用服务计划. 问题分析 导致上述问题的原因是,用户 ...

  6. EJB2.0版本的HelloWorld

    EJB2.0版本的HelloWorld   虽然EJB3.1已经出来了,可是EJB2.0的项目还需要维护啊.下面写个简单EJB2.0的HelloWorld程序,练练手.   环境: JBoss 4.0 ...

  7. vue+element ui项目总结点(二)table合计栏目,按照起始年份--截止年份 插入数据并向后追加数据以最后一条年份+1

    1.oninput 事件在用户输入时触发; <template> <div class="test_box"> <p>hell,你好</p ...

  8. bat 符号说明

    netstat -an|findstr 139 ipconfig/all findstr IP ipconfig/all |findstr   物理地址             定值选行 ipconf ...

  9. C语言二维数组作为函数参数

    设有整型二维数组a[3][4]如下:0   1   2   34   5   6   78   9  10  11 它的定义为:    int a[3][4]={{0,1,2,3},{4,5,6,7} ...

  10. Codeforces Round #316 (Div. 2) B Simple Game 贪心

    贪心,如果m分成的两个区间长度不相等,那么选长的那个区间最接近m的位置,否则选m-1位置,特判一下n等于1的情况 #include<bits/stdc++.h> using namespa ...