【题意】:给出一棵树,每条边上有一个权值,表示通过这条边的代价。现在有k个机器人在节点s,问用k个机器人访问完整棵树的节点的最少代价是多少。
【题解】:又是树dp+背包的题目。
设状态dp[u][k]表示以u为根节点的子树排了k个机器人下去访问完该子树的节点的最小代价。
如果k == 0,表示排了一个机器人下去访问完之后机器人又返回到节点u。
注意k == 0的时候必定是只有一个机器人下去然后返回,不会有多于一个机器人下去,因为这样肯定不是最优。
然后就是一个01背包 +分组背包,枚举容量时要逆序,因为用了滚动数组。
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 using namespace std;
13 #define pb push_back
14 #define lc(x) (x << 1)
15 #define rc(x) (x << 1 | 1)
16 #define lowbit(x) (x & (-x))
17 #define ll long long
18 #define pii pair<int, int>
19 #define mp make_pair
20 #define maxn 10050
21 #define maxm 1000050
22
23 int n, s, cnt;
24 int eh[maxn], tot;
25 int dp[maxn][15];
26 struct Edge {
27 int u, v, w, next;
28 }et[maxm];
29
30 void addedge(int u, int v, int w) {
31 Edge e = {u, v, w, eh[u]};
32 et[tot] = e;
33 eh[u] = tot++;
34 }
35
36 void init() {
37 tot = 0;
38 memset(eh, -1, sizeof(eh));
39 }
40
41 void dfs(int u, int fa) {
42 for(int i = eh[u]; i != -1; i = et[i].next) {
43 int v = et[i].v, w = et[i].w;
44 if(v == fa) continue;
45 dfs(v, u);
46 for(int j = cnt; j >= 0; j--) {
47 dp[u][j] += dp[v][0] + 2 * w;
48 for(int k = 1; k <= j; k++) {
49 dp[u][j] = min(dp[u][j], dp[u][j-k] + dp[v][k] + k * w);
50 }
51 }
52 }
53 }
54
55 int main() {
56 int u, v, w;
57 while(~scanf("%d%d%d", &n, &s, &cnt)) {
58 init();
59 memset(dp, 0, sizeof(dp));
60 for(int i = 0; i < n - 1; i++) {
61 scanf("%d%d%d", &u, &v, &w);
62 addedge(u, v, w), addedge(v, u, w);
63 }
64 dfs(s, -1);
65 printf("%d\n", dp[s][cnt]);
66 }
67 return 0;
68 }
69