洛谷P2015 二叉苹果树

mac2022-06-30  111

题面:

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2 5 \ / 3 4 \ / 1

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入输出格式

输入格式:

第1行2个数,NNNQ(1<=Q<=N,1<N<=200)Q(1<=Q<= N,1<N<=200)Q(1<=Q<=N,1<N<=200)

N表示树的结点数,Q表示要保留的树枝数量。接下来N−1N-1N1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式:

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

输入输出样例

输入样例

5 2 1 3 1 1 4 10 2 3 20 3 5 20

输出样例

21

分析:

f[i][j]f[i][j]f[i][j] 表⽰以i节点为根,保留j个树枝最多留下 多少个苹果。 只给左⼉⼦:f[i][j]=f[lson[i]][j−1]+vlson[i]f[i][j]=f[lson[i]][j-1]+vlson[i]f[i][j]=f[lson[i]][j1]+vlson[i] 只给右⼉⼦:f[i][j]=f[rson[i]][j−1]+vrson[i]f[i][j]=f[rson[i]][j-1]+vrson[i]f[i][j]=f[rson[i]][j1]+vrson[i] 都分⼀点:f[i][j]=max(f[lson[i]][k]+f[rson[i]][j−k−2]+vlson[i],vrson[i]).0<=k<=j−2f[i][j]=max(f[lson[i]][k]+f[rson[i]][j-k-2]+vlson[i],vrson[i]). 0<=k<=j-2f[i][j]=max(f[lson[i]][k]+f[rson[i]][jk2]+vlson[i],vrson[i]).0<=k<=j2.

另种思路在代码中说明

code:(搜索+dp)

#include<cstdio> #include<cmath> using namespace std; int n,q; struct ben { int to,last,val,dq;//to记录这条边的终点,last记录上一条边,dq记录边的起点,val记录边的权值 }a[205]; int f[205][205]; int cnt=1; int head[205];//head[i]表示以i为起点的边的编号 void add(int x,int y,int num)//连边函数 { a[cnt].to=y; a[cnt].last=head[x]; a[cnt].dq=x; a[cnt].val=num; head[x]=cnt; cnt++; } void search(int dq,int father) { for(int i=head[dq];i!=-1;i=a[i].last) { int b=a[i].to;//找到这条边的终点 if(b==father)continue;//不能为起点 f[b][1]=a[i].val;//初始化 search(b,dq);//搜索 for(int j=q;j>=1;j--) { for(int k=0;k<=j;k++) { if((j!=1&&j!=k)||dq==1) { f[dq][j]=fmax(f[dq][j],f[b][k]+f[dq][j-k]);//枚举中间点k,得出方程 } } } } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { head[i]=-1; }//初始化 for(int i=1;i<n;i++) { int x,y,num; scanf("%d%d%d",&x,&y,&num); add(x,y,num); add(y,x,num);//注意要连双向边 } search(1,0); printf("%d",f[1][q]); return 0; }

转载于:https://www.cnblogs.com/vercont/p/10210091.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)