贯彻树形dp第一维通常是节点编号的思想,f[i]表示以i点为根的子树的最大利润。根据题意,相连的两点不能同时取,故可想到增加一维表示i点取或不取:f[ i ][ 0 ]表示不取,f[ i ][ 1 ]表示取。
那么我们就可以列出状态转移方程了:
f[ i ][ 1 ] = ∑ f[ x ][ 0 ] + value[ i ] ;
f[ i ][ 0 ] = ∑ max( f[ x ][ 0 ],f[ x ][ 1 ]);
(x∈child[i])
即,如果选择了i点,那么i的直接孩子都不可以选;若i点不选,那么它的孩子选不选都合法,取最大值即可。
具体求法采用递归。在树上,常常用递归而不是循环,因为转移顺序一般是由下到上。也符合了多个子问题合并为一个问题的思想。
void dp(int x)
{
vis[x]=1;
for(int i=linkk[x];i;i=e[i].next)
if(!vis[e[i].y])
{
dp(e[i].y);
f[x][1]+=f[e[i].y][0];
f[x][0]+=max(f[e[i].y][0],f[e[i].y][1]);
}
f[x][1]+=v[x];
}
void init()
{
read(n);
for(int i=1;i<=n;++i) read(v[i]);
int x,y;
for(int i=1;i<n;++i)
{
read(x);read(y);
insert(x,y);insert(y,x);
}
}
void work()
{
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));//因为无根树,无法确定点之间的顺序关系,只能存双向边,则需标记是否访问。
dp(1);
ans=max(f[1][1],f[1][0]);
printf("%lld",ans);
}
int main()
{
init();
work();
return 0;
}
本文介绍了一种使用树形DP方法解决特定问题的技术。通过定义状态f[i][0]和f[i][1]来分别表示不选择节点i和选择节点i时其子树的最大利润,并给出了详细的状态转移方程及其实现代码。
1214

被折叠的 条评论
为什么被折叠?



