这个题是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. atomic用法

    memory order 源码变成可执行程序,一般由预编译,编译,汇编,链接.源码重排序一般分为编译期重排序和运行期重排序. 编译期重排序:编译器在不改变单线程程序的语义的前提下,可以重新安排语句的执 ...

  2. 【转】onAttachedToWindow()在整个Activity生命周期的位置及使用

    上篇博客实现圆角对话框样式的Activity中提到,若需实现圆角对话框Activity,需要在Activity的onAttachedToWindow()函数中做文章,那么就想问: onAttached ...

  3. TP框架设置验证码

    thinkphp框架有专门的的验证码生成的模块 public function shengcheng(){ $n = new \Think\Verify(); $n->entry(); } 下面 ...

  4. HDU 3032 Nim or not Nim? (Nim,sg函数)

    题意:给出几堆石子数量,每次可以取走一堆中任意数量的石头,也可以将一堆分成两堆,而不取.最后取走者胜. 思路:石子数量很大,不能直接算,sg打表找出规律:正常情况下a[i]=i,但是有例外的,就是i% ...

  5. UVA 11374 Airport Express (最短路)

    题目只有一条路径会发生改变. 常见的思路,预处理出S和T的两个单源最短路,然后枚举商业线,商业线两端一定是选择到s和t的最短路. 路径输出可以在求最短路的同时保存pa数组得到一棵最短路树,也可以用di ...

  6. 在Solr中配置中文分词IKAnalyzer

    李克华 云计算高级群: 292870151 交流:Hadoop.NoSQL.分布式.lucene.solr.nutch 在Solr中配置中文分词IKAnalyzer 1.在配置文件schema.xml ...

  7. 如何修改IOS的默认字体

    The first is workaround wich is iterating over all the labels in your UIView and change the labels f ...

  8. WPF中HyperLink超链接的使用

    HyperLink超链接的简单使用:  XAML里面: <TextBlock> <Hyperlink NavigateUri="http://www.baidu.com&q ...

  9. python基础一 day10(2)

    复习: # 三元运算符# 接收结果的变量 = 条件为真的结果 if 条件 else 条件为假的结果# 接收结果的变量 = “真结果” if 条件 else “假结果”## 命名空间 和 作用域# 三种 ...

  10. C++类型强制转换<转>

    转载:http://www.cnblogs.com/goodhacker/archive/2011/07/20/2111996.html C风格的强制类型转换(Type Cast)很简单,不管什么类型 ...