P2015 二叉苹果树

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2015 二叉苹果树相关的知识,希望对你有一定的参考价值。

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 二叉苹果树的主要内容,如果未能解决你的问题,请参考以下文章

P2015 二叉苹果树

P2015 二叉苹果树

P2015 二叉苹果树

P2015 二叉苹果树

P2015 二叉苹果树

洛谷—— P2015 二叉苹果树