适用于树形 的情况,父节点的情况依赖于子节点的取舍,往往采用 进行动态转移
也有可能反过来,总而言之是具有一定依赖性的
树形背包
//u为现在的根节点,cnt为当前选择了几个节点
void dfs(int u, int cnt){
for(auto v: G[u]){//遍历所有子节点
//将u的价值先传递给j,为什么cnt-1是因为要给 u, v 留出一个位置 , 这啥时候写的神秘笔记
rep(j, 0, cnt-1){
dp[v.first][j] = dp[u][j] + v.second;
}
//处理
dfs(v.first, cnt - 1);
rep(j, 1, t){
dp[u][j] = max(dp[u][j], dp[v.first][j-1]);
}
}
}例题
二叉苹果树
题意
略
题解
下保留保留 点至少需要 纸条开始遍历,向上向下传
void dfs(int u, int f, int cnt){
if(cnt > k) return; //想要到 u 点必须至少保留 cnt 条边
for(auto x : G[u]){
int v = x.first;
int w = x.second;
if(v == f) continue;
rep(i, cnt + 1, k){
dp[v][i] = dp[u][i - 1] + w;
}
dfs(v, u, cnt + 1);
rep(i, cnt + 1, k){
dp[u][i] = max(dp[u][i], dp[v][i]);
}
}
return;
}偷天换日
题意
现在有一个博物馆,每个走廊的尽头不是一个有藏品的房间,就是两条走廊。
房间内有若干副画,价值不同,偷画和经过走廊都需要时间。
警察还有 就将到达门口,小偷如果第 秒的时候还在博物馆,他就要被抓了,请问小偷在不被抓的情况下,最多偷几幅画
输入按照深度优先给出,房间和走廊的数量总共不超过 300
每组数据给出 , 代表藏品数量,如果是 0 说明是走廊,如果不是,那么后面跟的 组 代表画的价值和偷画的时间 , 不超过 30
题解
易错点在于需要使用 去读取数据,直接看代码
struct node{
int to, ww, tt;
};
int n;
vector<node> G[N];
vii dp(N, vi(610));
int p = 0;
void dfs1(int u){ //dfs 读取数据部分
int t, x; cin >> t >> x;
p ++;
G[u].push_back({p, 0, 2 * t});
int v = p;
if(x == 0){
dfs1(v);
dfs1(v);
}else{
rep(i, 1, x){
int w, t; cin >> w >> t;
p ++;
G[v].push_back({p, w, t});
}
}
return;
}
void dfs2(int u, int time){ //树形背包部分
//cout << u << " " << time << endl;
if(time >= n) return;
for(auto tmp : G[u]){
int v = tmp.to;
//cout << u << " " << v << " " << tmp.ww<< endl;
//cout << "? " << u << " " << v << endl;
int t = tmp.tt;
int w = tmp.ww;
rep(i, time + t, n){
dp[v][i] = dp[u][i - t] + w;
}
dfs2(v, time + t);
rep(i, time + t, n){
dp[u][i] = max(dp[u][i], dp[v][i]);
}
}
return;
}
void solve(){
cin >> n;
dfs1(0);
dfs2(0, 0);
int res = 0;
rep(i, 0, n - 1){
res = max(res, dp[0][i]);
}
cout << res << endl;
return;
}