cod5565二叉苹果树

题目大意

有一棵二叉的苹果树,(既然是树的话那就有n个节点和n-1个枝条),现在我们要剪枝,使得留下m个枝条,但是有些枝条上是有苹果的,求剪哪些枝条才能够保住最多的苹果。(虽然题目没说,但由于这是一棵苹果树,你只能剪叶子节点的枝条,所以是不能贪心的)

输入格式

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

输出格式

剩余苹果的最大数量。

输入样例

5 2

1 3 1

1 4 10

2 3 20

3 5 2021

题目分析

不能贪心,而且这是二叉树,二叉树,是最好写树形dp的数据结构了!

烦恼的是苹果是长在枝条上的,其实你可以把苹果挪到这个枝条连接的子节点上,因为如果减去这个枝条,就不会保留子节点。那么我们就从选枝条变成了选节点。并且由于一定要留根节点,所以m++.

如果用f[i][j]表示第i个节点的话,不难推导,f[i][j]=max(f[l[i]][k]+f[l[i]][j-k-1]+a[i]);用dfs来进行这个过程,每次dfs你需要的f[i][j]。

具体还是看代码吧。

代码

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
int n,m;
int l[101],r[101],a[101];
int bian[101][4],sum[101][4];
int f[101][101];
bool vis[101],vv[101][101];
void dfs(int now){//转化成二叉树
	int i;
	vis[now]=1;
	for(i=1;i<=bian[now][0];i++)//寻找子节点
		if(vis[bian[now][i]]==0){
			if(l[now]==0){
				l[now]=bian[now][i];
                                a[l[now]]=sum[now][i];//挪动苹果
				dfs(bian[now][i]);
			}
			else{
				r[now]=bian[now][i];a[r[now]]=sum[now][i];
				dfs(bian[now][i]);
			}
		}
}
void find(int i,int j){
	int k;
	if(vv[i][j]==1)return;
	vv[i][j]=1;//记忆化,如果已经搜出了f[i][j]就不用搜了
	if(j==0||i==0)return;
	for(k=0;k<=j-1;k++){
		find(l[i],k);
		find(r[i],j-k-1);//先弄出你需要的f
		f[i][j]=max(f[i][j],f[l[i]][k]+f[r[i]][j-k-1]+a[i]);//dp方程
	}
}
int main()
{
    int i,j,x,y,apple;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n-1;i++){
    	scanf("%d%d%d",&x,&y,&apple);
    	bian[x][0]++;bian[x][bian[x][0]]=y;sum[x][bian[x][0]]=apple;
    	bian[y][0]++;bian[y][bian[y][0]]=x;sum[y][bian[y][0]]=apple;
    }
    dfs(1);
    m++;//要选择根节点1
    find(1,m);
    printf("%d",f[1][m]);
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值