树形DP-----HDU4003 Find Metal Mineral

Find Metal Mineral

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 1079

Problem Description

  Humans  have  discovered  a  kind  of  new  metal  mineral  on  Mars  which  are  distributed  in point‐like  with  paths  connecting  each  of  them  which  formed  a  tree.  Now  Humans  launches  k robots on Mars to collect them, and due to the unknown reasons, the landing site S of all robots is identified in advanced, in other word, all robot should start their job at point S. Each robot can return  to  Earth  anywhere,  and  of  course  they  cannot  go  back  to  Mars.  We  have  research  the information of all paths on Mars, including its two endpoints x, y and energy cost w. To reduce the total energy cost, we should make a optimal plan which cost minimal energy cost.

Input

  There are multiple cases in the input. In each case: The first line specifies three integers N, S, K specifying the numbers of metal mineral, landing site and the number of robots. The  next  n‐1  lines  will  give  three  integers  x,  y,  w  in  each  line  specifying  there  is  a  path connected point x and y which should cost w. 1<=N<=10000, 1<=S<=N, 1<=k<=10, 1<=x, y<=N, 1<=w<=10000.

Output

  For each cases output one line with the minimal energy cost.

Sample Input

3 1 1 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1

Sample Output

3 2

Hint

In the first case: 1->2->1->3 the cost is 3; In the second case: 1->2; 1->3 the cost is 2;

dp[pos][num]表示以pos为根节点的子树下,用去num个机器人,所得到的最小值

特别的是当num==0的时候,dp[pos][0]表示用一个机器人去走完所有子树,最后又回到pos这个节点

状态转移:dp[pos][num]=min∑{dp[pos_j][num_j]+w_j},pos_j是pos的所有儿子,

当num_j==0的时候,和别的时候不同,特别处理一下就好。

状态转移并不难,最精华的,我不认为是状态转移,而是转移时使用的那个“分组背包”思想。

使用一维数组的“分组背包”伪代码如下:

for 所有的组i

for v=V..0

for 所有的k属于组i

f[v]=max{f[v],f[v-c[k]]+w[k]}

上面那个状态转移时,要把num个机器人分给所有它的儿子,状态太多了,不好做,用“分组背包”实在太帅了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4
 5 using namespace std;
 6
 7 struct Edge{
 8 int to;
 9 int value;
10 int next;
11 }edge[2*10008];
12 int head[10008],dp[10008][12];
13 int N,S,K,total;
14
15 inline int MIN(int a,int b)
16 {
17     if(a<b) return a;
18     return b;
19 }
20 void addEdge(int start,int end,int value)
21 {
22     edge[total].to=end;edge[total].value=value;
23     edge[total].next=head[start];head[start]=total++;
24
25     edge[total].to=start,edge[total].value=value;
26     edge[total].next=head[end],head[end]=total++;
27 }
28
29 void DP(int source,int pre)
30 {
31     for(int i=head[source];i!=-1;i=edge[i].next)
32     {
33         int to=edge[i].to;
34         if(to==pre) continue;
35         DP(to,source);
36         for(int j=K;j>=0;j--)
37         {
38             dp[source][j]+=dp[to][0]+2*edge[i].value;
39             for(int k=1;k<=j;k++)
40                 dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);
41         }
42     }
43 }
44
45 int main()
46 {
47    while(scanf("%d %d %d",&N,&S,&K)!=EOF)
48    {
49        memset(dp,0,sizeof(dp));
50        memset(head,-1,sizeof(head));
51        total=0;
52
53        int x,y,cost;
54        for(int i=1;i<N;i++)
55        {
56            scanf("%d %d %d",&x,&y,&cost);
57            addEdge(x,y,cost);
58        }
59        DP(S,-1);
60        printf("%d\n",dp[S][K]);
61    }
62     return 0;
63 }

思路和其他人差不多,谈谈自己是怎么理解的吧:
     首先,用两数组建立无向树,还是第一次,费了不少功夫。定义一个结构代表边edge[i]={to,next,value},其中edge[i]表示第i条边,to是边的末点,value就不说了,next代表的是同一父节点边方向相同的与此边相邻的左边的边的编号,其中最左是-1。以此为基础建立一个边数组(注意数组大小是顶点数的两倍),还有用一个head[i]数组来表示最右边的边的编号。

  解释这一段代码,当时写的理解的不是很好:

 1 void DP(int source,int pre)
 2 {
 3     for(int i=head[source];i!=-1;i=edge[i].next)
 4     {
 5         int to=edge[i].to;
 6         if(to==pre) continue;
 7         DP(to,source);
 8         for(int j=K;j>=0;j--)
 9         {
10             dp[source][j]+=dp[to][0]+2*edge[i].value;
11             for(int k=1;k<=j;k++)
12                 dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);
13         }
14     }
15 }

第一层for循环查找与节点source相连的各条边,to是此边对应的末点,若此边是叶子节点则to==pre(由于节点最左边的边访问完以后,只有到他父节点的边,这里只能用continue,因为不确定访问的顺序,return不合适),递归访问子节点此时应用01背包,由于dp[source][0]比较特殊单独处理,一棵子树对应一个分组,dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);也比较好理解。

树形DP-----HDU4003 Find Metal Mineral

时间: 2024-09-30 10:55:33

树形DP-----HDU4003 Find Metal Mineral的相关文章

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

题目大意:用m个机器人去遍历有n个节点的有根树,边权代表一个机器人通过这条边的代价,求最小代价. 题目分析:定义状态dp(root,k)表示最终遍历完成后以root为根节点的子树中有k个机器人时产生的总代价.则状态转移方程为: dp(root,k)=min(dp(root,k),dp(son,j)+dp(root,k-j)+j*w(root,son))  j>0 要注意,当j为0的时候表示遍历完son这个子树后所有的机器人都回到root.可以证明,如果让遍历son的所有的机器人都回到root,那

hdu 4003 Find Metal Mineral 树形DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on Mars to collect

hdu 4003 Find Metal Mineral 【树形dp,分组背包】

题目:hdu 4003 Find Metal Mineral 题意:火星上发现了一些n个矿厂,有 k 个机器人从 s 点出发采矿,给出路段间的花费cost,求最小的花费采所有的矿. 分类:树形dp + 分组背包 分析:结论1:假如我们从 i点出发k个机器人采完以 k 为根节点的所有矿又回到 i 点,那么花费为 i 为根节点的cost 的和 乘以 k. 对于每个节点,定义状态:dp[i][j] 用 j 个机器人去采以 i 为根节点的子树的所有矿石的最小花费 状态转移方程:dp[father][nu

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on

hdu4003(树形dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 题意:给定一棵n个节点的树,遍历每条数边都需要费用cost,现在给定k个机器人,要求用这个k个机器人遍历整棵树,使得经过的费用和最小,n<=10000. 分析:dp[u][j]表示有j个机器人不回来的最小值,dp[u][0]表示有一个机器人回来的最小值,即没有一个机器停留在那颗子树上.至于为甚么只考虑一个机器人回来的原因是同时派多个机器人下去,如果回来的人越多,走重复路线会越多,耗费越多. 这

xtu summer individual 6 E - Find Metal Mineral

Find Metal Mineral Time Limit: 1000ms Memory Limit: 65768KB This problem will be judged on HDU. Original ID: 400364-bit integer IO format: %I64d      Java class name: Main Humans have discovered a kind of new metal mineral on Mars which are distribut

【转】【DP_树形DP专辑】【9月9最新更新】【from zeroclock&#39;s blog】

树,一种十分优美的数据结构,因为它本身就具有的递归性,所以它和子树见能相互传递很多信息,还因为它作为被限制的图在上面可进行的操作更多,所以各种用于不同地方的树都出现了,二叉树.三叉树.静态搜索树.AVL树,线段树.SPLAY树,后缀树等等.. 枚举那么多种数据结构只是想说树方面的内容相当多,本专辑只针对在树上的动态规划,即树形DP.做树形DP一般步骤是先将树转换为有根树,然后在树上进行深搜操作,从子节点或子树中返回信息层层往上更新至根节点.这里面的关键就是返回的信息部分,这个也没一般性的东西可讲

HDOJ 4003 Find Metal Mineral

题意: 一棵有权树,从根结点中放入 K 个机器人.求用这 K 个机器人遍历全部的结点最少的权值和. 思路: 1. dp[u][i] 表示给以 u 为根节点的子树放 i 个机器人,遍历其子树所须要的最小权值. 2. 关键在于 dp[u][0] 的理解,表示:最后停留在以 u 为根节点的子树下 0 个机器人,而且遍历了 u 子树的最小权值和. 3. 以下的步骤就变成和分组背包类似的情况了,根节点 u 给孩子 v 放多少个机器人. 4. dp[u][i] = min(dp[u][i], dp[u][j

HDU 4003 - Find Metal Mineral

Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 3368    Accepted Submission(s): 1569 Problem Description Humans have discovered a kind of new metal mineral on Mars which are d