voiddfs(int u, int fa){ for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].to; if (v == fa) { // 遇到父节点跳过 continue; } dfs(v, u); // 按照深度优先,先dfs孩子节点 num[u] += num[v] + 1; // dfs的同时求一下该点为根节点子树的边数
// 为什么当前保存的边数 j 要倒着dp?和01背包的滚动数组类似, // dp[u][j]在更新后,不会在后面的更新中用到,而正着dp就会出问题了, // 那样你会用到在加入 v 子节点后,被更新过的dp[u][j]的值,显然是错误的 for (int j = min(num[u], q); j >= 0; j--) { // k正着反着倒无所谓 // 这里有个细节,为什么 k 取的是min{num[v], j - 1}而不是min{num[v], j}? // 因为,既然我要把点 v 加进来,那肯定是要有一条边把 u 和 v // 连起来,那条边就是e[i],所以 k 最多取的是min{num[v], j - 1} for (int k = min(num[v], j - 1); k >= 0; k--) { dp[u][j] = max(dp[u][j], dp[u][j - k - 1] + dp[v][k] + e[i].co); } } } }
intmain(){ memset(head, -1, sizeof(head)); scanf("%d%d", &n, &q); for (int i = 0; i < n - 1; i++) { int ff, tt, cc; scanf("%d%d%d", &ff, &tt, &cc); add_edge(ff, tt, cc); } dfs(1, -1); printf("%d\n", dp[1][q]); return0; }