[POJ1155]TELE(树形dp)
2016-05-04 21:56
316 查看
题目描述
传送门题解
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<iostream> #include<cstring> #include<cstdio> 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; } }
总结
自己感觉到了之前树形背包的坑在哪里。。大概就是状态的问题,现在更新的状态用的原始的状态不能是刚更新过的状态。
相关文章推荐
- android--线程池
- 使用Powershell注销指定用户
- Spring Web MVC实现Restful Web Service
- 地图之CLLocationManager的使用
- 会场安排问题
- 获取主机名和IP
- java并发编程(13)--线程间协作的两种方式:wait、notify、notifyAll和Condition
- UVA 684 (矩阵行列式)
- IT十八掌掌第一天课程总结
- mysql的with rollup
- <Android 应用 之路> 天气预报(三)
- <Android 应用 之路> 天气预报(三)
- viso2010画平行四边形
- MyEclipse复制一行的快捷键用不了问题
- Servlet上下文监听器
- online_judge_1524
- oracle 数据库-查询
- for迭代求小孩年龄
- Redis jedis 简单例子
- 微信支付:“当前页面的URL未注册”