……

解题报告: luogu P2015

明天就考试了,可是树形\(dp\)还是不会。
题目链接:P2015 二叉苹果树
其实就是这题的双倍经验啦。
动态转移方程是

\[f[i][j]=max(f[i][j],f[i][i-k-1]+f[i_{son}][k]+e[i].w) \]

这里\(f[i][j]\)代表从以\(i\)为根的子树中合法留\(j\)个树枝的最大剩余值。

\(Code\):

#include<cmath>
#include<cstdio> 
#include<iostream>
const int MAXN=105;
using namespace std;
typedef long long ll;
ll f[MAXN][MAXN],c;
int n,s,l,r,root,tot[MAXN];
struct node
{
	int to,nxt;
	ll w;
}e[MAXN<<1];
int head[MAXN],cnt=0;
int deg[MAXN];
void add(int u,int v,ll c)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	e[cnt].w=c;
	head[u]=cnt;
}
int dfs(int cur,int fa)
{
	tot[cur]=0;
	for(int i=head[cur];i;i=e[i].nxt)
	{
		int j=e[i].to;
		if(j==fa) continue;
		int son=dfs(j,cur)+1;
		tot[cur]+=son;
		for(int k=tot[cur];k>=0;k--)
		{
			for(int v=0;k-v-1>=0&&v<=son;v++) f[cur][k]=max(f[cur][k],f[cur][k-v-1]+f[j][v]+e[i].w);
		}
	}
	return tot[cur];
}
int main()
{
	scanf("%d%d",&n,&s);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d%lld",&l,&r,&c);
		add(l,r,c);
		add(r,l,c);
		deg[l]++,deg[r]++;
	}
	for(int i=1;i<=n;i++) if(deg[i]==2) root=i;
	dfs(root,0);
	printf("%lld\n",f[root][s]);
	return 0;
}

好像这就是树形背包了呢。

posted @ 2020-03-06 19:38  童话镇里的星河  阅读(115)  评论(0编辑  收藏  举报