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]);
}

 

posted @ 2023-04-10 10:03  董晓  阅读(1667)  评论(1)    收藏  举报