ural1018

题目大意:

有一棵二叉苹果树,共有N个结点,编号为1~N,树根编号一定是1用两个结点的编号来描述每一根树枝。现在这颗树枝条太多了,需要剪枝。但树枝上长有苹果。请问给定需要保留的树枝数量Q,求出最多能留住多少苹果。

输入格式:第12个数,NQ(1<=Q<= N,1<N<=100)N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。每根树枝上的苹果不超过30000个。

输出格式:一个数,最多能留住的苹果的数量。

开始学习树形DP,先水了一道题。

这个DP很好想,f[i][j]表示以i为根选j个苹果的max

f[i][j]=max(f[i][j],f[i的左儿子][k]+f[i的右儿子][j-k-1]+f[i][1])

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=300;
struct node{
	int x,y,z,next,other;
}sa[N];int len=0,first[N];
int n,k;
void ins(int x,int y,int z)
{
	len++;
	sa[len].x=x;
	sa[len].y=y;
	sa[len].z=z;
	sa[len].next=first[x];
	first[x]=len;
}
struct trnode
{
	int l,r;
	trnode()
	{
		l=r=0;
	}
}tr[N];
bool tf[N];
int f[N][N];
void dfs(int x)
{
	for(int i=first[x];i!=-1;i=sa[i].next)
	{
		int y=sa[i].y;
		if(tf[y]==true)
		{
			tf[y]=false;
			f[y][1]=sa[i].z;
			if(tr[x].l==0) tr[x].l=y;
			else           tr[x].r=y;
			dfs(y);
		}
	}
}
int tr_dp(int x,int m)
{
	if(f[x][m]!=-1) return f[x][m];
	int maxx=0;
	for(int i=0;i<=m-1;i++)
	{
		int ls=i,rs=(m-1)-i;
		int lans=tr_dp(tr[x].l,ls);
		int rans=tr_dp(tr[x].r,rs);
		   maxx=max(maxx,lans+rans+f[x][1]);
	}
	f[x][m]=maxx;
	return f[x][m];
}
int main()
{
	scanf("%d%d",&n,&k);
	memset(first,-1,sizeof(first));
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		ins(x,y,z);
		ins(y,x,z);
	}
	memset(tf,true,sizeof(tf));
	memset(f,-1,sizeof(f));
	tf[1]=false;
	dfs(1);
	for(int i=1;i<=n;i++) f[i][0]=0;
	f[1][1]=0;
	printf("%d\n",tr_dp(1,k+1));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值