题目链接: http://xcacm.hfut.edu.cn/oj/problem.php?id=1102
题目大意:树上取点。父亲出现了,其儿子包括孙子...都不能出现。给定预算,问最大值。
解题思路:
把树形背包的模板改一改。
首先对于叶子结点,直接初始化就行了。这步不可以跳过,因为存在负权,仅仅依靠最后的max是不行的。
对于普通结点,首先不考虑当前根,先把全部预算分给儿子。
即for(int j=W; j>=1; j--)
for(int k=1; k<=j; k++)
最后再做一次dp[root][cost~m]=max(dp[root][cost~m],w[root])
意思为要么取所有儿子,要么只取根。
#include "cstdio" #include "iostream" #include "cstring" using namespace std; #define maxn 1200 int c[maxn],w[maxn],dp[maxn][maxn],head[maxn],tol; int n,W,u; struct Edge { int to,next; }e[maxn]; void addedge(int u,int v) { e[tol].to=v; e[tol].next=head[u]; head[u]=tol++; } void dfs(int root) { int i=root,cost=c[root]; if(head[root]==-1) for(int i=cost;i<=W;i++) dp[root][i]=w[root]; for(int a=head[root];a!=-1;a=e[a].next) { int t=e[a].to; dfs(t); for(int j=W; j>=1; j--) for(int k=1; k<=j; k++) dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]); } for(int i=cost;i<=W;i++) dp[root][i]=max(dp[root][i],w[root]); } int main() { //freopen("in.txt","r",stdin); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&W); for(int i=2;i<=n;i++) { scanf("%d",&u); addedge(u,i); } for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=n;i++) scanf("%d",&w[i]); dfs(1); printf("%d ",dp[1][W]); }
2600 | 2013217098 | Accepted |
7176
|
56
|
C++/Edit | 1188 B | 2014-10-20 20:18:43 |