P2015 二叉苹果树
这道树形dp我又跪了。。
这道题给你二叉树,共有\(n-1\)条边,每条边有边权,只有在父亲结点被保留的情况下才能算进答案,求保留\(m\)条边的答案最大值。
我拿起来就开始写,后来才发现是边权啊!
翻题解发现,还是那个老思路:边权变为点权。只要把每一条边的边权弄到终点的点权即可。
由于是树,所以不会有一个点有多个边连入,所以放心地写。
状态方程还是那个dp[u][j] = std::max(dp[u][j], dp[u][j - k] + dp[v][k])
我们添加点权的时候在那个dp[u][1]
里面加上去就好了。
其他都跟前面的是一样的。
我没用到这个二叉树的性质
代码:
#include<cstdio>
#include<algorithm>
const int maxn = 1005;
struct Edges
{
int next, to;
} e[maxn];
int head[maxn], tot;
int dp[maxn][maxn];
int n, m;
int weight[maxn];
void link(int u, int v)
{
e[++tot] = (Edges){head[u], v};
head[u] = tot;
}
int dfs(int u)
{
int ans = 1;
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
int t = dfs(v);
ans += t;
for(int j = ans; j; j--)
{
for(int k = 1; k <= m; k++)
{
if(j - k > 0) dp[u][j] = std::max(dp[u][j], dp[u][j - k] + dp[v][k]);
}
}
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
link(u, v);
dp[v][1] += w;
}
dfs(1);
printf("%d\n", dp[1][m + 1]);
return 0;
}