hdu 1561 树形DP入门题

来源:互联网 发布:身体乳推荐知乎 编辑:程序博客网 时间:2024/05/16 17:24

http://www.cnblogs.com/zjh10/articles/2032294.html

这个题目是说 每个点有权值,有些点的得到需要先得到某点,问你选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,

依赖关系形成森林,要先把树转换成森林才能进行树形DP

增加一个根节点0即可

dp[i][j]表示以i为根的子树选择j个点所能达到的最优值

答案即为dp[0][m+1]:因为增加了一个根节点

View Code
#include<stdio.h>
#include<string.h>
int n,m;
int num[250];
int map[250][250];
int dp[250][250];
bool vis[250];
int max(int a,int b){
return a>b?a:b;
}
void dfs(int p)
{
int i,j,k;
vis[p]=true;
for(i=1;i<=num[p];i++)
{
int t=map[p][i];
if(!vis[t]) dfs(t);
for(j=m;j>=2;j--)//选择1个的状态不用更新了,因为是强制要加进去的,即必须先选择的
{
for(k=1;k<j;k++)
{
if(dp[t][j-k]!=-1&&dp[p][k]!=-1)
dp[p][j]=max(dp[p][j],dp[p][k]+dp[t][j-k]);
}
}
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m),n||m)
{
int a,b;
dp[0][1]=0;
memset(num,0,sizeof(num));
for(i=1;i<=n;i++){
scanf("%d%d",&a,&b);
dp[i][1]=b;
map[a][++num[a]]=i;
}
m++;//增加一个点,森林转换成树
for(i=0;i<=n;i++){
dp[i][0]=0;vis[i]=0;
for(j=2;j<=m;j++){
dp[i][j]=-1;
}
}
dfs(0);
printf("%d\n",dp[0][m]);
}
return 0;
}



原创粉丝点击