码迷,mamicode.com
首页 > Web开发 > 详细

HDU 4003 Find Metal Mineral (树形DP,树形分组背包,经典)

时间:2015-09-18 23:23:36      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

 

 

题意:给定一棵树图,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 <iostream>
 5 #define pii pair<int,int>
 6 #define max(x,y) (x>y?x:y)
 7 #define min(x,y) (x<y?x:y)
 8 #define INF 0x3f3f3f3f
 9 #define LL long long
10 using namespace std;
11 const int N=10050;
12 
13 struct node
14 {
15     int from,to,len,next;
16     node(){};
17     node(int from,int to,int len,int next):from(from),to(to),len(len),next(next){};
18 }edge[N*2];
19 
20 int head[N],dp[N][12], n, K, edge_cnt;
21 void add_node(int from,int to,int len)
22 {
23     edge[edge_cnt]=node(from,to,len,head[from]);
24     head[from]=edge_cnt++;
25 }
26 
27 void DFS(int t,int far)
28 {
29     node e;
30     for(int i=head[t]; i!=-1; i=e.next) //相当于枚举‘组‘
31     {
32         e=edge[i];
33         if(e.to^far)
34         {
35             DFS(e.to, t);
36             for(int j=K; j>=0; j-- )  //枚举背包容量
37             {
38                 dp[t][j]+=dp[e.to][0]+e.len*2;
39                 for(int u=1; u<=j; u++)    //枚举买dp[e.to][u]这件商品
40                     dp[t][j]=min(dp[t][j], dp[t][j-u]+dp[e.to][u]+u*e.len );
41             }
42         }
43     }
44 }
45 
46 
47 
48 int main()
49 {
50     freopen("input.txt", "r", stdin);
51     int a,b,c,s;
52     while(~scanf("%d%d%d",&n,&s,&K))
53     {
54         memset(head, -1, sizeof(head));
55         memset(dp, 0, sizeof(dp));
56         edge_cnt=0;
57         for(int i=1; i<n; i++)
58         {
59             scanf("%d%d%d",&a,&b,&c);
60             add_node(a,b,c);
61             add_node(b,a,c);
62         }
63         DFS(s, -1);
64         printf("%d\n", dp[s][K]);
65     }
66     return 0;
67 }
AC代码

 

HDU 4003 Find Metal Mineral (树形DP,树形分组背包,经典)

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4820463.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!