/**//* 题意:有依赖的背包,要用树dp 《浅谈几类背包题》里提到的《金明的预算方案》类似
代码参照这里写的:http://hi.baidu.com/darkgtbd/blog/item/4bca2b16d955624420a4e9dc.html
1<=N<=100000, 1<=G<=10000 数据很恐怖 题目有个地方要注意到: 3. The alpc who has underling is an officer (Every officer’ number is no more than 500, like alpc21, alpc32). 也就是说非叶子节点最多有500个 所以只需开dp[500][G]即可
按照论文的方法,泛化背包合并,从O(NC^2) 用类似01背包的方法降到 O(NC) u对儿子v dfs之前,先对dp[v][j]初始为dp[u,j]+val[v] 即强制放进去v 然后修改对v的上限 最后合并,即更新
*/ #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> #include<map> #include<cmath> #include<cstdlib> #include<iostream>
using namespace std;
const int INF = 1000000000; const int MAXN = 100010;
struct Edge { int v; Edge *next; };
Edge *E[MAXN] , edges[MAXN*2] , *pE;
bool leaf[MAXN]; int weight[MAXN] , val[MAXN]; int dp[505][10005];
inline void add(int u,int v) { pE->v = v; pE->next = E[u]; E[u] = pE++; }
void dfs(int u, int C) { for(Edge *it = E[u] ; it ; it = it->next) { int v = it->v; if(!leaf[v]) { for(int j = 0 ; j <= C-weight[v]; j++)//强制放进去v dp[v][j] = dp[u][j] + val[v]; dfs(v,C-weight[v]);//修改上限 for(int j = weight[v] ; j <= C ; j++)//两者合并 对于dp[v,j]只有j<=C-weight[v]时才是正确的结果 if(dp[u][j] < dp[v][j-weight[v]]) dp[u][j] = dp[v][j-weight[v]]; } else { for(int j = C ; j >= weight[v] ; j--) if(dp[u][j] < dp[u][j-weight[v]] + val[v]) dp[u][j] = dp[u][j-weight[v]] + val[v]; } } }
int main() {
#ifdef ONLINE_JUDGE #else freopen("in", "r", stdin); #endif
int n ,g , f ; while( ~scanf("%d%d",&n,&g) ) { pE = edges; for(int i = 0 ; i <= n ; i++) { E[i] = NULL; leaf[i] = true; } weight[0] = val[0] = 0;
for(int i = 1; i <= n ;i++) { scanf("%d%d%d", &weight[i] , &val[i] , &f ); if(f == i)f = 0; leaf[f] = false; add(f,i); }
for(int i = 0 ;i <= g ; i++) dp[0][i] = 0; dfs(0,g);
int ans = 0; for(int j = 0 ; j <= g; j++) if(ans < dp[0][j]) ans = dp[0][j]; printf("%d\n",ans); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|