HDU 4003【树型DP+背包】

题意:

给出一棵树,选择一个s点为根,最多给出k个机器人,从根结点开始,求遍历所有的结点的最小花费。

解题思路:

树存在递归结构,对每个结点,他和他的后代组成一棵树,且他所有的儿子都是一棵树,则该结点的状态一般由其子树递推而来,每棵子树达到最优时,才能推出根结点的最优解,可采用递归DFS很方便处理。本题可以设DP[n][i]表示结点为n的子树放进i个机器人时的最小花费,其中DP[n][0]特殊,表示放进一个机器人又返回了该结点,结点n的所有儿子结点为DP[si][i],难点是如何从DP[si][0...k]组合成i从而使DP[n][i]最小,即从每个结点中选取合适的DP[s][j],使得所有的j加起来刚好等于i,并且使DP[n][i]最小。忘了这个是哪类背包问题,分类背包?组合背包?

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5
6 using namespace std;
7 const int MAXN = 10000 + 1;
8 const int MAXK = 10 + 1;
9 const int INF = 0x7fffffff;
10
11 struct TNode
12 {
13 TNode(int n = 0, int d = 0, int ne = 0): node(n), dist(d), next(ne){}
14 int node, dist, next;
15 }Node[MAXN * 4];
16 int N, S, K;
17 int DP[MAXN][MAXK], Pos[MAXN];
18 int EndPos;
19
20 void init()
21 {
22 for(int i = 1; i <= N; ++i)
23 {
24 Pos[i] = i;
25 Node[i].next = 0;
26 }
27 memset(DP, 0, sizeof(DP));
28 EndPos = N;
29 }
30 void addEdge(int f, int t, int v)
31 {
32 ++EndPos;
33 Node[Pos[f]].next = EndPos;
34 Node[Pos[f] = EndPos] = TNode(t, v, 0);
35 }
36
37 int getMin(int a, int b)
38 {
39 return a < b ? a : b;
40 }
41
42 void dfs(int father, int node)
43 {
44 for(int ix = Node[node].next; ix != 0; ix = Node[ix].next)
45 {
46 if(Node[ix].node != father)
47 dfs(node, Node[ix].node);
48 }
49 for(int ix = Node[node].next; ix != 0; ix = Node[ix].next)
50 {
51 if(Node[ix].node == father)
52 continue;
53 for(int k = K; k >= 0; --k)
54 {
55 DP[node][k] += DP[Node[ix].node][0] + Node[ix].dist * 2;
56 for(int i = 1; i <= k; ++i)
57 {
58 DP[node][k] = getMin(DP[node][k], DP[Node[ix].node][i] + DP[node][k - i] + Node[ix].dist * i);
59 }
60 }
61 }
62 }
63
64 int main()
65 {
66 freopen("in.txt", "r", stdin);
67 int f, t, v;
68 while(scanf("%d%d%d", &N,&S, &K) == 3)
69 {
70 init();
71 for(int i = 1; i <= N - 1; ++i)
72 {
73 scanf("%d%d%d", &f, &t, &v);
74 addEdge(f, t, v);
75 addEdge(t, f, v);
76 }
77
78 dfs(-1, S);
79 printf("%d\n", DP[S][K]);
80 }
81 return 0;
82 }

你可能感兴趣的:(HDU)