#树形dp#JZOJ 1661 洛谷 2015 二叉苹果树

题目

在一棵二叉苹果树上,保留k根枝条,使剩余的苹果数最大。


分析

树形dp, f [ i ] [ j ] f[i][j] f[i][j]表示第i个节点保留j根枝条的最大苹果数
状态转移方程: f [ 当 前 的 点 ] [ j ] = max ⁡ ( f [ 当 前 的 点 ] [ j − k − 1 ] + f [ 孩 子 ] [ k ] + e [ i ] . w ) f[当前的点][j]=\max(f[当前的点][j-k-1]+f[孩子][k]+e[i].w) f[][j]=max(f[][jk1]+f[][k]+e[i].w)
在O(n)的时间内可以求出答案


代码

#include 
#include 
using namespace std;
struct tree{int y,w,next;}son[201];
int f[101][101],b[101],n,q,ls[101];
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int min(int a,int b){return (a<b)?a:b;}
int max(int a,int b){return (a>b)?a:b;}
void dfs(int u,int last){
	for (int i=ls[u];i;i=son[i].next)
	if (son[i].y!=last){//没有走回去
		dfs(son[i].y,u);//找孩子
		b[u]+=b[son[i].y]+1;//b表示枝条的个数
		for (int j=min(q,b[u]);j>=1;j--)//当前点的枝条
		for (int k=min(b[son[i].y],j-1);k>=0;k--)//孩子的枝条
		f[u][j]=max(f[u][j],f[u][j-k-1]+f[son[i].y][k]+son[i].w);
	}
}
int main(){
	n=in(); q=in();
	for (int i=1;i<n;i++){
		int x=in(),y=in(),w=in();
		son[~-(i<<1)]=(tree){y,w,ls[x]}; ls[x]=~-(i<<1);
		son[i<<1]=(tree){x,w,ls[y]}; ls[y]=i<<1;
	}
	dfs(1,0);
	return !printf("%d",f[1][q]);
}

你可能感兴趣的:(树形dp)