【SSL】1605&【洛谷】P2015二叉苹果树
发布日期:2021-05-07 09:21:37 浏览次数:36 分类:原创文章

本文共 1624 字,大约阅读时间需要 5 分钟。

【SSL】1605&【洛谷】P2015二叉苹果树

Time Limit:1000MS Memory Limit:65536K

Description

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。

Input

第1行2个数,N和Q(1<=Q<= N,1

Output

一个数,最多能留住的苹果的数量。

Sample Input

5 21 3 11 4 102 3 203 5 20

Sample Output

21

思路

我们设ma[x][y]为边的值,因为树是双向的,所以要再记录ma[y][x]。
设tree[v,1]为节点v的左子树,tree[v,2]为节点v的右子树,然后我们再递归建树。
定义f[i][j]表示以i为节点的根保留j条边的最大值
f[v][k]=max(f[v][k],(f[tree[v][1]][i]+f[tree[v][2]][k-i-1]+num[v]))
我们枚举i就可以了,用记忆化搜索的形式(dfs)来具体实现。
F[1][Q+1]就是答案。
因为题目中给的是边的权值,而我们在处理时将每条边的权值全赋给其所连的父节点和子节点中的子节点(将关于边的问题转化为关于点的问题),所以最后是Q+1,表示点的数目。

代码

#include<iostream>#include<cstdio>#include<cstring>using namespace std;long long a[110][110],f[110][110],l[110],r[110],num[110],n;void maketree(long long v);void build(long long x,long long y,long long o){       if(o)r[x]=y;    else l[x]=y;    num[y]=a[x][y],a[x][y]=a[y][x]=-1,maketree(y);    return;}void maketree(long long x){       bool lr=1;    for(long long i=1;i<=n;i++)        if(a[x][i]>-1)        {           	lr=!lr,build(x,i,lr);            if(lr)return;        }    return;}long long DP(long long x,long long y){   	if(f[x][y]>-1)return f[x][y];	if(y==0)return f[x][y]=0;	if(!l[x]&&!r[x])return f[x][y]=num[x];	for(long long k=0;k<y;k++)f[x][y]=max(f[x][y],DP(l[x],k)+DP(r[x],y-k-1)+num[x]);	return f[x][y];}int main(){   	ios::sync_with_stdio(false);	long long q,i,j,x,y,t;	memset(f,-1,sizeof(f)),memset(a,-1,sizeof(a));	for(cin>>n>>q,i=1;i<n;i++)cin>>x>>y>>t,a[x][y]=a[y][x]=t;	maketree(1),cout<<DP(1,q+1);	return 0;}
上一篇:Vue中Better-scroll滚动插件的基本使用
下一篇:js数据结构--队列--常见操作

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月06日 21时53分51秒