题目链接:http://www.vijos.org/Problem_Show.asp?id=1180
——————————————————————————————————————————————
题目思路:
基本的树型dp,记忆化搜索。
1、先将森林按照左孩子右兄弟存储。
2、dp[i][j] = max{dp[i.bro][j], dp[i.son][j-k-1]+dp[i.bro][k]+ val[i] }
i表示当前处理节点为i,j表示已经选了的课程数。
方程含义:1、取当前i节点,则剩下的j-1们课程,在孩子中选j-k-1门,在兄弟中选k门。
2、不取当前节点,则只能在兄弟中选j门。
——————————————————————————————————————————————
题目细节:
注意初始化。
——————————————————————————————————————————————
源代码:
#include <iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
#define maxn 310
#define max(a,b) ((a)>(b)?(a):(b))
struct treetype
{
int fat;
int son;
int bro;
int val;
}tree[maxn];
int dp[maxn][maxn];
int n = 0,m = 0;
int solve(int i,int cur)
{
int j = 0;
int ans = 0;
if(i == n+1)
return 0;
if(dp[i][cur]!=-1)
return dp[i][cur];
for(j = 0;j<=cur-1;j++)
ans = max(ans,solve(tree[i].son,j)+solve(tree[i].bro,cur-j-1)+tree[i].val);
dp[i][cur] = max(ans,solve(tree[i].bro,cur));
return dp[i][cur];
}
int main()
{
int i = 0;
int f = 0;
int ans = 0;
scanf("%d%d",&n,&m);
for(i = 0;i<=n;i++)
{
tree[i].fat = n+1;
tree[i].son = n+1;
tree[i].bro = n+1;
}
memset(dp,-1,sizeof(dp));
for(i = 1;i<=n;i++)
{
scanf("%d%d",&f,&tree[i].val);
tree[i].fat = f;
if(tree[f].son == n+1)
tree[f].son = i;
else
{
int next = tree[f].son;
while(tree[next].bro != n+1)
next = tree[next].bro;
tree[next].bro = i;
}
}
ans = solve(tree[0].son,m);
printf("%d\n",ans);
return 0;
}