[POJ1155]TELE(树形dp)

题目描述

传送门

题解

size[i]表示以i为根的子树中有几个叶子节点。
f[i][j]表示以i为根的子树中,选j个叶子节点的最大收益。
那么f[x][j+k]=max(f[x][j+k],last[j]+f[v[i]][k]-c[i]);
注意现在更新的状态用的原始的状态不能是刚更新过的状态,所以要用一个last数组来存之前的状态然后更新。

代码

#include
#include
#include
using namespace std;const int max_n=3e3+5;
const int max_e=max_n*2;
const int INF=2e9;int n,m,k,x,y;
int f[max_n][max_n],size[max_n],last[max_n];
int tot,next[max_e],point[max_n],v[max_e],c[max_e];inline void add(int x,int y,int z){++tot;next[tot]=point[x];point[x]=tot;v[tot]=y;c[tot]=z;}
inline void treedp(int x,int fa){for (int i=point[x];i;i=next[i])if (v[i]!=fa){treedp(v[i],x);for (int j=0;j<=size[x];++j) last[j]=f[x][j];for (int j=0;j<=size[x];++j)for (int k=1;k<=size[v[i]];++k)f[x][j+k]=max(f[x][j+k],last[j]+f[v[i]][k]-c[i]);size[x]+=size[v[i]];}
}
int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n-m;++i){scanf("%d",&k);for (int j=1;j<=k;++j){scanf("%d%d",&x,&y);add(i,x,y),add(x,i,y);}}for (int i=1;i<=n;++i)for (int j=1;j<=n;++j)f[i][j]=-INF;memset(size,0,sizeof(size));for (int i=n-m+1;i<=n;++i) scanf("%d",&f[i][1]),size[i]=1;treedp(1,0);for (int i=m;i>=0;--i)if (f[1][i]>=0){printf("%d\n",i);return 0;}
}

总结

自己感觉到了之前树形背包的坑在哪里。。
大概就是状态的问题,现在更新的状态用的原始的状态不能是刚更新过的状态。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部