您的位置:首页 > 其它

JZOJ 5344. 【NOIP2017模拟9.3A组】摘果子

2017-09-03 14:53 393 查看

题目大意

给n个物品,每个物品有他唯一的父亲,选物品的时候选了他的父亲才能选他。

每个物品有代价,有获利。

问在总代价不超过m的情况下能获得的最大获利。

题解

裸的树形背包。

用多叉树转二叉树的方法过不了N≤2000的数据,超时(时间复杂度O(n3))。

那么我们基于整棵树的DFS序做一遍DP。

设f[i][j]表示做到dfs序中的第i个,总代价为j。设dfs序中的第i个点为p号点,那么

f[i][j]=max(f[i+1][j−w[p]]+c[p],f[i+siz[p]][j])

其中,f[i+siz[p]][j]表示不选p,那么其子树也不会被选到,f[i+1][j−w[p]]+c[p]表示选p。

注意了,这个DP必须倒着做。因为只有这样才能够保证更新到f[i][j]的状态在更新f[i][j]前已经是最优的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 2010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define eg(i,x) for(i=head[x];i;i=edge[i].next)
using namespace std;
struct note{
int to,next;
};note edge[N*2];
int i,j,k,l,n,m,x;
int u,v,tot,ans;
int head
,c
,w
;
int dfn
,tar
;
int f

,fa
,siz
;
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
void dfs(int x){
int i;
dfn[x]=++k;
tar[k]=x;siz[x]=1;
eg(i,x)
if(fa[x]!=edge[i].to){
fa[edge[i].to]=x;
dfs(edge[i].to);
siz[x]+=siz[edge[i].to];
}
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d%d",&c[i],&w[i]);
fo(i,1,n-1){
scanf("%d%d",&u,&v);
lb(u,v);lb(v,u);
}
dfs(1);
memset(f,128,sizeof(f));
f[n+1][0]=0;
fd(i,n,1){
x=tar[i];
fo(j,0,m){
f[i][j]=f[i+siz[x]][j];
if (j>=w[x]) f[i][j]=max(f[i][j],f[i+1][j-w[x]]+c[x]);
if (f[i][j]<0) f[i][j]=0;
}
}
printf("%d",f[1][m]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: