-------------------------题目链接--------------------------
题目大意:
其实这道题读完后我们能很明显感觉到是一个背包问题,ACboy所能攻击的次数就是“背包”的容量大小,而每个城堡攻击一次就可以得到里面的宝石相当于每个城堡占背包体积1,城堡里的宝石数目就是他们相应的价值,让我们求出可以达到的最大价值。而唯一的不同就是有些东西要装必须先装其他的东西(即要打某些城堡时必须先打别的),有了约束条件后这就转化成了一个树形背包问题,也就是说要想选儿子,必须先选父亲。
对于树形背包问题,我们一般设出一个虚拟节点来连接没有父节点的节点,然后从这个虚拟节点开始dfs。
题目思路:
对于树形背包问题,我们一般设 f [ i ] [ j ] 为给第i个点的子树分配 j 个空间所能达到的最大值;接下来对于子树的最大值计算就跟01背包相似了。代码中有详细说明
题目代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<cstring>
#include<cstdio>
#define maxn 205
using namespace std;
int vis[maxn];
int dp[maxn][maxn];//表示给第i个根节点的子树一共分配j个空间所能得到的最多财宝
vector<int>v[maxn];
int n,m;
void dfs(int root)//获得这个根节点下的dp值
{
//vis[root]=1;
for(int i=0;i<v[root].size();i++)
{
int nxt=v[root][i];//儿子i
if(!vis[nxt]&&v[nxt].size())
{
dfs(nxt);//得到这个节点在各个允许的空间下的最大值
}
//一共有m个空间,要分给下面的所有子节点,每个城堡相当于体积都为1
for(int j=m;j>1;j--)//从体积为m往下推
{
for(int k=1;k<j;k++)//给其他子树留了k
{
dp[root][j]=max(dp[root][j],dp[root][k]+dp[nxt][j-k]);
}
}
}
}
int main(void)
{
int a,b;
while(~scanf("%d%d",&n,&m)&&(n+m))
{
m++;//多了一个0号节点虚拟节点
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++)//加了0号节点也要清一下
v[i].clear();
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
v[a].push_back(i);
for(int j=1;j<=m;j++)//初始化,相当于这棵树并没有建立起来
{
dp[i][j]=b;
}
}
dfs(0);
printf("%d\n",dp[0][m]);
}
return 0;
}
呼呼