二叉苹果树
xianghaoyu666 · · 个人记录
二叉苹果树
题目链接
凌晨0:31
分析
给你一棵树,只能保留
因为是在树上,又有容量(树枝个数)和最大价值,不难想到树上背包
树上背包
所以设
由背包问题的优化,可以换为滚动数组,将
那么从节点
其中
那么实现便是
::::info[DFS代码]{open}
void dfs(int x,int fa){//x:以x为根的子树 fa:当前节点的父亲(不重复)
for(auto i:g[x]){//遍历子树
if(i.first==fa){//遍历到父亲,就下一个(跳过)
continue;
}
dfs(i.first,x);//统计子树信息
for(int j=q;j>=1;j--){//枚举容量(树枝数) 原为 dp[i][j][k] 以i为子树,前j个枝,选k个,苹果数最大,压维后需逆序
for(int k=0;k<j;k++){//枚举当前树枝容量
dp[x][j]=max(dp[x][j],dp[x][j-k-1]+dp[i.first][k]+i.second);//更新,注意是j-k-1不是j-k,因为 x->i 连边也应加上
}
}
}
return;
}
::::
时间复杂度
优化
但还可以再优化一点
因为
跑一遍预处理
::::info[预处理]{open}
void solve(int x,int fa){
for(auto i:g[x]){//遍历子树
if(i.first==fa){//遍历到父亲,就下一个(跳过)
continue;
}
solve(i.first,x);//统计子树信息
siz[x]+=siz[i.first]+1;//树枝数=字数树枝数+1
}
return;
}
::::
再判断
注意这里
AC Code
::::warning[请勿copy]
//二叉苹果树
//树形dp
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n,q;
vector<pair<int,int>>g[310];//链式前向星亦可
int dp[110][110];//dp[i][j]表示在以i为根的子树中,留下j个树枝,最多能留住的苹果数量
int siz[110];
void solve(int x,int fa){
for(auto i:g[x]){//遍历子树
if(i.first==fa){//遍历到父亲,就下一个(跳过)
continue;
}
solve(i.first,x);//统计子树信息
siz[x]+=siz[i.first]+1;//树枝数=字数树枝数+1
}
return;
}
void dfs(int x,int fa){//x:以x为根的子树 fa:当前节点的父亲(不重复)
for(auto i:g[x]){//遍历子树
if(i.first==fa){//遍历到父亲,就下一个(跳过)
continue;
}
dfs(i.first,x);//统计子树信息
for(int j=min(siz[x],q);j>=1;j--){//枚举容量(树枝数) 原为 dp[i][j][k] 以i为子树,前j个枝,选k个,苹果数最大,压维后需逆序
for(int k=0;k<min(siz[i.first]+1,j);k++){//枚举当前树枝容量 (<!)
dp[x][j]=max(dp[x][j],dp[x][j-k-1]+dp[i.first][k]+i.second);//更新,注意是j-k-1不是j-k,因为 x->i 连边也应加上
}
}
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
g[a].push_back({b,c});
g[b].push_back({a,c});//存树(图)
}
solve(1,0);
dfs(1,0);//从1开始遍历
cout<<dp[1][q];//在1节点,留q个树枝,最多能留住的苹果数
return 0;
}
::::
总结
这是一道很模板的树上背包,但由于是树枝(边)上有价值,所以要细心改动一些,在细节上也要小心
很像选课这道题,但除了边上有价值以外,这道题一定是一棵二叉树!!!所以只有两条边,没有选课麻烦,但这个通解总能行
一般来说,树形dp都是先统计子树的答案,再汇总到根来计算,如
几个经典模型:
- 树上背包
- 最小覆盖集(点)
- 最大独立集
- 最小支配集(边)
树形dp题
- [P1122] 最大子树和(模板)
- [P2610] 旅游(树的直径的求法)
- [P1270] “访问”美术馆(输入……)