E18【模板】树上背包 P2014 [CTSC1997] 选课
E18【模板】树上背包 P2014 [CTSC1997] 选课_哔哩哔哩_bilibili
P2014 [CTSC1997] 选课 - 洛谷
$f_{x,j}$ 表示以 $x$ 为根的子树,选了 $j$ 门课程的最大学分。
如果新儿子 $y$ 选 $k$ 门课程,则 $y$ 及旧儿子只能选 $j-k$ 门课程,
$$ f_{x,j}=\max_{y\in son(x)}(f_{x,j-k}+f_{y,k}),j\in [m,1],k\in [0,j-1] $$
树上 01 背包,逆序枚举 $j$
从0号点向没有先修课的课程连边,把森林转化成一颗树,0号点的为必选点,所以共选 $m+1$ 门。
// 树上背包 O(n*m*m) #include<bits/stdc++.h> using namespace std; const int N=305; vector<int> e[N]; int n,m,w[N]; int f[N][N]; //f[x][j]表示以 x 为根的子树,选了 j 门课程的最大学分 void dfs(int x){ f[x][1]=w[x]; for(int y:e[x]){ dfs(y); for(int j=m; j; j--) for(int k=0; k<j; k++) f[x][j]=max(f[x][j],f[x][j-k]+f[y][k]); } } int main(){ scanf("%d%d",&n,&m); ++m; //加上0号点 for(int i=1,k; i<=n; i++){ scanf("%d%d",&k,&w[i]); e[k].push_back(i); } dfs(0); printf("%d",f[0][m]); }
// 树上背包+优化 O(n*m) #include<bits/stdc++.h> using namespace std; const int N=305; vector<int> e[N]; int n,m,w[N]; int f[N][N]; //f[x][j]表示以 x 为根的子树,选了 j 门课程的最大学分 void dfs(int x){ for(int y:e[x]){ for(int j=0;j<=m-1;j++) f[y][j]=f[x][j]+w[y]; dfs(y); for(int j=1;j<=m;j++) f[x][j]=max(f[x][j],f[y][j-1]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1,k; i<=n; i++){ scanf("%d%d",&k,&w[i]); e[k].push_back(i); } dfs(0); printf("%d",f[0][m]); }
P1064 [NOIP 2006 提高组] 金明的预算方案 - 洛谷
// 树上背包 O(n*m*m) TLE #include<bits/stdc++.h> using namespace std; const int N=65; vector<int> e[N]; int m,n,v[N],w[N]; //m总钱数,n物品数,v价格,w价值 int f[N][32005]; //f[x][j]表示以 x 为根的子树,花费为 j 时的最大收益 void dfs(int x){ for(int i=v[x];i<=m;i++)f[x][i]=w[x]; for(int y:e[x]){ dfs(y); for(int j=m; j>=v[x]; j--) for(int k=0; k<=j-v[x]; k++) f[x][j]=max(f[x][j],f[x][j-k]+f[y][k]); } } int main(){ scanf("%d%d",&m,&n); for(int i=1,x;i<=n;i++){ scanf("%d%d%d",&v[i],&w[i],&x); w[i]*=v[i]; e[x].push_back(i); } dfs(0); printf("%d\n",f[0][m]); }
E75【模板】树上背包 P2015 二叉苹果树 - 董晓 - 博客园
E76 树上背包 P1064 [NOIP2006 提高组] 金明的预算方案 - 董晓 - 博客园
// 树上背包+优化 O(n*m) #include<bits/stdc++.h> using namespace std; const int N=65; vector<int> e[N]; int m,n,v[N],w[N]; //m总钱数,n物品数,v价格,w价值 int f[N][32005]; //f[x][j]表示以 x 为根的子树,花费为 j 时的最大收益 void dfs(int x){ for(int y:e[x]){ for(int j=0; j<=m-v[y]; j++) f[y][j]=f[x][j]+w[y]; dfs(y); for(int j=v[y]; j<=m; j++) f[x][j]=max(f[x][j],f[y][j-v[y]]); } } int main(){ scanf("%d%d",&m,&n); for(int i=1,x;i<=n;i++){ scanf("%d%d%d",&v[i],&w[i],&x); w[i]*=v[i]; e[x].push_back(i); } dfs(0); printf("%d\n",f[0][m]); }
浙公网安备 33010602011771号