题意分析
给出一个N个点的二叉树,树上有边权,求留下Q个树枝能够获得的最大收益为多少。
dp[i][j] d p [ i ] [ j ] 表示在以 i i 为根的节点,留下个分支,的最大收益值。
设
u
u
为当前遍历到的根节点,为访问的子节点,
e[i].w
e
[
i
]
.
w
当前边的边权。则状态转移方程如下:
dp[u][j]=max(dp[u][j],dp[u][j−k]+dp[v][k−1]+e[i].w)
d
p
[
u
]
[
j
]
=
m
a
x
(
d
p
[
u
]
[
j
]
,
d
p
[
u
]
[
j
−
k
]
+
d
p
[
v
]
[
k
−
1
]
+
e
[
i
]
.
w
)
还要注意循环顺序,循环j要从m到0,而k是任意的,这与转移的顺序有关系
#include "bits/stdc++.h"
using namespace std;
const int nmax = 1e6 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef struct {
int to, nxt, w;
} Edge;
Edge e[nmax << 1];
int dp[1010][1010];
int head[nmax], tot, n, m;
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void add(int u, int v, int w) {
e[tot].to = v;
e[tot].nxt = head[u];
e[tot].w = w;
head[u] = tot++;
}
void getdp(int u , int fa) {
for (int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) getdp(v, u);
else continue;
for (int j = m; j >= 0; --j)
for (int k = j ; k >= 1 ; --k)
dp[u][j] = max(dp[u][j], dp[u][j - k] + dp[v][k - 1] + e[i].w);
}
}
int main() {
init();
scanf("%d %d", &n, &m);
for (int i = 0; i < n - 1; ++i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
getdp(1, -1);
printf("%d\n", dp[1][m]);
return 0;
}