这个题目是说 每个点有权值,有些点的得到需要先得到某点,问你选M个点能够得到的最大值
很明显是有依赖的背包,而且应该是有依赖中有依赖(虽然我觉得题目并没有很明确地说)~
这样的话 我们就构建dp[i][j],i为i号点,j为它选了里面的几个点。。。。。
这样的话 我们就发现其实是个树,点的值取决于子点的选法。
方程dp[k][j]=max(dp[k][j],dp[k][j-kk]+dp[t[k][i]][kk])
表示在第i个k的子点中选kk个点加上目前k号点选j-kk个点与直接在k号点选j个点谁更优。。。
我们可以知道dp[k][1]=val[k],因为选一个点的话必须选自己 = =
于是这样的题可以有两种基本写法,一是先确定了1的地位(这样或许算是常数优化),二是马后炮最后才补上这个val,第二种更好理解 所以附上第一种的代码~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define tt int
inline tt max(tt a,tt b)
{
return a>b?a:b;
}
inline tt min(tt a,tt b)
{
return a<b?a:b;
}
int dp[205][205];
int t[205][205];
int top[205];
int v[205];
int m;
void dfs(int k)
{
int i,j,kk;
v[k]=1;
for(i=0;i<=top[k];i++)
{
if(!v[t[k][i]]) dfs(t[k][i]);
for(j=m;j>=2;j--) //只有2后面的状态需要更新
{
for(kk=1;kk<j;kk++)
{
if(dp[t[k][i]][kk]!=-1 && dp[k][j-kk]!=-1)
{
dp[k][j]=max(dp[k][j],dp[k][j-kk]+dp[t[k][i]][kk]);
}
}
}
}
}
int main()
{
int n,i,j,k,ii,jj,sum,ans;
int x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n+m==0) break;
for(i=0;i<=n;i++) top[i]=-1;
dp[0][1]=0; //自己为空点
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
t[x][++top[x]]=i;
dp[i][1]=y;
}
for(i=0;i<=n;i++)
{
dp[i][0]=0; // 0为不选任何一个点~
for(j=2;j<=m;j++)
{
dp[i][j]=-1;
}
v[i]=0;
}
m++;//提前加一个点,就是0号
dp[0][m]=-1;
dfs(0);
printf("%d\n",dp[0][m]);
}
return 0;
}