输入样例
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
输出样例
13
分析
将二叉苹果树转为多叉树即可,怎么转呢?就是把处理过的所有子树合并看成左子树,右边第一棵树看做右子树。
DP的转移方程也是一样的
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
]
,
f
[
y
]
[
k
]
+
f
[
i
]
[
j
−
k
−
1
]
+
v
[
x
]
[
y
]
)
f[i][j]=max(f[i][j],f[y][k]+f[i][j−k−1]+v[x][y])
f[i][j]=max(f[i][j],f[y][k]+f[i][j−k−1]+v[x][y])意为以i为根选j条边
给子节点k条边
给别的子节点
j
−
k
−
1
j−k−1
j−k−1条边(子节点和父节点相连时也用了一条边,所以别的子节点拿少一条)
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int v[100001],a[5001][5001],f[5001][5001];
int s[5001][5001],c[100001],vis[100001];
void dp(int x)
{
vis[x]=1;
for(int i=1;i<=c[x];i++)
{
int y=s[x][i];
if(vis[y]==1) continue;
dp(y);
for(int j=m;j>=0;j--)
{
for(int k=j-1;k>=0;k--)
{
f[x][j]=max(f[x][j],f[y][k]+f[x][j-k-1]+a[x][y]);
}
}
}
}
int main()
{
int x;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x>>v[i];
a[x][i]=v[i];
s[x][++c[x]]=i;
}
dp(0);
cout<<f[0][m];
return 0;
}