http://www.luogu.org/problem/show?pid=2014
(注意题目数据范围有误,建议开数组到2000)
经典树形依赖背包问题。
因为可能出现森林,所有要建立一个虚结点0,将森林中所有树的根节点作为结点0的儿子
f[i][j]表示以i为根选j个课程
f[u][j] = max(f[u][j], f[u][j-k]+f[v][k]); //v是u的儿子
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ms(i,j) memset(i, j, sizeof(i));
using namespace std;
int n,m;
int t;
int w[2005];
vector<int>G[2005];
int f[2005][2005];
void dfs(int u)
{
for (int i=1;i<=m;i++)
f[u][i] = w[u];//必选u
for (int i=0;i<G[u].size();i++)
{
int v = G[u][i];
dfs(v);
for (int j=t;j>=2;j--)
{
for (int k=1;k<j;k++)
{
f[u][j] = max(f[u][j], f[u][j-k]+f[v][k]);
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1;i<=n;i++)
{
int ki;
scanf("%d%d", &ki, &w[i]);
G[ki].push_back(i);
}
t = m+1;//增加了一个虚结点0,将森林转为树,所以t=m+1
dfs(0);
printf("%d\n", f[0][m+1]);
return 0;
}