传送门
树形DP入门题。这类题目被称为背包树形DP,又称有树形依赖的背包问题。虽说是入门题,但第一次写并不是很顺利,网上的解法都是二维的,但我只会先用高维做再转成低维的,搞的就很难受。
三维解法,思路见注释
#include<iostream>
#include<cstdio>
#include<vector>
#define maxn 305
using namespace std;
int n,m,f[maxn][maxn][maxn];
vector<int> edge[maxn];
inline int in()
{
char a=getchar();
while(a<'0'||a>'9')
{
a=getchar();
}
int t=0;
while(a>='0'&&a<='9')
{
t=(t<<1)+(t<<3)+a-'0';
a=getchar();
}
return t;
}
void dp(int now)
{
for(int i = 0; i < edge[now].size(); ++i) //考虑前i个子树
{
int go = edge[now][i];
dp(go);
for(int j = m+1; j >= 1; j--) //背包容量
{
f[now][i+1][j] = f[now][i][j];
for(int k = 1; k < j; k++) //第i棵子树选择物品数
{
f[now][i+1][j] = max(f[now][i+1][j], f[go][ edge[go].size() ][k] + f[now][i][j-k]);
}
}
}
int main()
{
n=in(),m=in();
for(int i=1;i<=n;i++)
{
int fa=in();
f[i][0][1]=in();
for(int j = 1; j <= m+1; ++j)
f[i][j][1] = f[i][0][1];
edge[fa].push_back(i);
}
dp(0);
printf("%d\n",f[0][edge[0].size()][m+1]);
return 0;
}
可以用滚动数组优化成二维的
#include<iostream>
#include<cstdio>
#include<vector>
#define maxn 305
using namespace std;
int n,m,f[maxn][maxn];
vector<int> edge[maxn];
inline int in()
{
char a=getchar();
while(a<'0'||a>'9')
{
a=getchar();
}
int t=0;
while(a>='0'&&a<='9')
{
t=(t<<1)+(t<<3)+a-'0';
a=getchar();
}
return t;
}
void dp(int now)
{
for(int i = 0; i < edge[now].size(); ++i) //考虑前i个子树
{
int go = edge[now][i];
dp(go);
for(int j = m+1; j >= 1; j--) //背包容量
{
for(int k = 1; k < j; k++) //第i棵子树选择物品数
{
f[now][j] = max(f[now][j], f[go][k] + f[now][j-k]);
}
}
}
}
int main()
{
n=in(),m=in();
for(int i=1;i<=n;i++)
{
int fa=in();
f[i][1]=in();
edge[fa].push_back(i);
}
dp(0);
printf("%d\n",f[0][m+1]);
return 0;
}