P2015 二叉苹果树
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2015 二叉苹果树相关的知识,希望对你有一定的参考价值。
题意:
一个完全二叉树,n个点,n-1个边,每个边都有边权,问保留q个边,所能保留的最大边权是多少
题解:
树形dp
dp[u][i]表示u的子树上保留i条边,至多保留的苹果数目
如何建立状态转移方程呢?
我们设v是u的一个子节点,现在以u为根的子树要保留i个边,那我们可以让v保留j个边,u和v之间就有一个边,u只需要保留i-j-1个边即可(相当于u的儿子节点v分担了一部分任务,另一部分其他负责)
这样可得:
dp[u][i] = max(dp[u][i],dp[v][j]+w[u][v]+dp[u][i-j-1])
循环i的时候为倒叙循环,j的话无所谓
因为,dp[u][i]还没更新时,里面存的是除v之外的情况,所以dp[u][i-j-1]表示的是除v节点的子树外,其他保存i-j-1边的最大情况,我们要用这个值去更新dp[u][i],更新后的dp[u][i]表示以u为根包含i个边(此时就包含v了),我们必须要逆序才能保证这一过程,有01背包优化的那种感觉,所以这个dp[u][i]相当于是优化的
for(int j=min(sz[u],q);j>=1;j--){
for(int k=0;k<=min(sz[v],j-1);k++){
dp[u][j]=max(dp[u][j],dp[u][j-k-1]+dp[v][k]+w);
}
}
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
const int maxn=220;
vector<pair<int,int> >vec[maxn];
int dp[maxn][maxn];
int sz[maxn];
int n,q;
void dfs(int u,int fa){
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i].first;
int w=vec[u][i].second;
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v]+1;
for(int j=min(sz[u],q);j>=1;j--){
for(int k=0;k<=min(sz[v],j-1);k++){
dp[u][j]=max(dp[u][j],dp[u][j-k-1]+dp[v][k]+w);
}
}
}
}
int main()
{
cin>>n>>q;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
vec[u].push_back(make_pair(v,w));
vec[v].push_back(make_pair(u,w));
}
dfs(1,-1);
cout<<dp[1][q];
}
以上是关于P2015 二叉苹果树的主要内容,如果未能解决你的问题,请参考以下文章