洛谷P2015 二叉苹果树

题面:

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

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

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

2   5
 \ / 
  3   4
   \ /
    1

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

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

输入输出格式

输入格式:

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

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

每行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 [ l s o n [ i ] ] [ j − 1 ] + v l s o n [ i ] f[i][j]=f[lson[i]][j-1]+vlson[i] f[i][j]=f[lson[i]][j1]+vlson[i]
只给右⼉⼦: f [ i ] [ j ] = f [ r s o n [ i ] ] [ j − 1 ] + v r s o n [ i ] f[i][j]=f[rson[i]][j-1]+vrson[i] f[i][j]=f[rson[i]][j1]+vrson[i]
都分⼀点: f [ i ] [ j ] = m a x ( f [ l s o n [ i ] ] [ k ] + f [ r s o n [ i ] ] [ j − k − 2 ] + v l s o n [ i ] , v r s o n [ i ] ) . 0 < = k < = j − 2 f[i][j]=max(f[lson[i]][k]+f[rson[i]][j-k-2]+vlson[i],vrson[i]). 0<=k<=j-2 f[i][j]=max(f[lson[i]][k]+f[rson[i]][jk2]+vlson[i],vrson[i]).0<=k<=j2.

另种思路在代码中说明

code:(搜索+dp)

#include
#include
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

你可能感兴趣的:(题解,洛谷刷题)