Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=1561
【思路】
树形DP,可以采用一般的记忆化搜索,也可以根据树的后序遍历进行DP。
可以直接对树进行DP,也可以将其转化为二叉树再进行DP。转化为二叉树的好处是实现容易,思维也清晰。
注意把0结点作为实际上的根节点,并要将它跟其他结点区分开来,因为0结点是不计算在内的。
每个结点要么不包含(连同其子树),要么包含一部分(或者全部)。所以就这两种状态进行转移。
【代码】
#include <iostream>
using namespace std;
const int maxn = 200;
const int MAX = 99999999;
int brother[maxn+5];
int son[maxn+5];
int value[maxn+5];
int dp[maxn+5][maxn+5];
void init(int n)
{
int i, j;
for (i=0; i<=n; i++)
{
value[i] = 0;
brother[i] = son[i] = -1;
for (j=0; j<=n; j++)
{
dp[i][j] = -1;
}
}
}
int solve(int v, int k)
{
int ans, i, t1, t2;
if (v==-1 || k==0) return 0;
if (dp[v][k]!=-1) return dp[v][k];
ans = solve(brother[v], k);
for (i=0; i<k; i++)
{
t1 = solve(son[v], i);
t2 = solve(brother[v], k-i-1);
if (t1+t2+value[v]>ans)
ans = t1+t2+value[v];
}
return dp[v][k] = ans;
}
int main()
{
int n, m;
int a, ans, t;
int i;
while(scanf("%d %d", &n, &m)!=EOF)
{
if (n==0 && m==0) break;
init(n);
for (i=1; i<=n; i++)
{
scanf("%d %d", &a, &value[i]);
brother[i] = son[a];
son[a] = i;
}
ans = -1;
i = son[0];
do
{
t = solve(i, m);
if (t>ans)
ans = t;
i = brother[i];
}while(i!=-1);
printf("%d\n", ans);
}
return 0;
}