自己理解
2025-07-18 16:02:32
发布于:浙江
1阅读
0回复
0点赞
#include <cstdio>
#include <cctype>
#include <algorithm>
#define maxn 105
inline int read() {
int d=0;char ch=getchar();while(!isdigit(ch))ch=getchar();
while(isdigit(ch)){d=d*10+ch-48;ch=getchar();}return d;
}
int n, k;
int w[maxn], v[maxn], d[maxn];
int head[maxn], ver[maxn], nxt[maxn], tot;
inline void add(int u, int v) {
ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}
int dep[maxn]; // 每个节点的深度
int f[maxn][maxn][maxn], g[maxn][maxn][maxn];
int stk[maxn], tots; // 为了方便转移,我们用一个栈维护u的祖先
void dfs(int u) {
stk[++tots] = u;
for(int p = head[u]; p; p = nxt[p]) {
int v = ver[p];
dep[v] = dep[u]+d[v], dfs(v);
// 先向下递归,算出子树的答案
// 当前要统计的子树为v
for(int i = 1; i <= tots; ++i) { // 枚举祖先
for(int j = k; j >= 0; --j) { // 这里j的顺序不能反,因为我们是拿之前的状态去更新新的状态
f[u][stk[i]][j] += f[v][stk[i]][0];
g[u][stk[i]][j] += f[v][u][0];
// 注意在增加一棵子树的时候,状态表示的范围扩大了
// 所以必须先将一个状态拿出来先更新,否则f和g表示的答案不包括当前子树
for(int l = 1; l <= j; ++l) {
// 当前子树v总共建了l个伐木场,此时u前面的子树建了j-l个伐木场
// u不建伐木场,此时子树中未被处理的木料要全部运往stk[i]
f[u][stk[i]][j] = std::min(f[u][stk[i]][j], f[v][stk[i]][l]+f[u][stk[i]][j-l]);
// u建伐木场,子树中未被处理的木料需要运往u
g[u][stk[i]][j] = std::min(g[u][stk[i]][j], f[v][u][l]+g[u][stk[i]][j-l]);
}
}
}
}
// 统计点u的贡献,更新最终答案
for(int i = 1; i <= tots; ++i) {
for(int j = k; j >= 1; --j)
f[u][stk[i]][j] = std::min(f[u][stk[i]][j]+w[u]*(dep[u]-dep[stk[i]]), g[u][stk[i]][j-1]);
f[u][stk[i]][0] += w[u]*(dep[u]-dep[stk[i]]);
// 要把u中的木料运到stk[i],需要花费w[u]*(dep[u]-dep[stk[i]])
// 我们不需要考虑u子树的花费,因为它们已经在之前被算过了
}
--tots;
}
int main() {
n = read(), k = read();
for(int i = 1; i <= n; ++i) {
w[i] = read(), v[i] = read(), d[i] = read();
add(v[i], i);
}
dfs(0);
printf(~~~~~~);
return 0;
}
全部评论 1
给我点赞
2025-07-18 来自 浙江
0
有帮助,赞一个