JZOJ 3914. 【NOIP2014模拟11.2B组】人品问题


题目:

传送门


题意:

给出一个二叉树,求在这棵树上按照 d f s dfs dfs序取 k k k个点权可以取得的最大值


分析:

爽快树形 d p dp dp,不解释
但是需要注意,当根节点只有一个子节点时要特判,另一个要注意的是我们必须取到 k k k
如果漏了上述两点,那么就会造成 100 → 50 100→50 10050的惨案


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
using namespace std;
inline LL read(){
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
LL n=read(),k=read();
LL x[1005],son[1005][20],len[1005];
LL w[1005][1005];
void dt(LL u)
{
	if(!len[u]) return;
 	LL v1=son[u][0],v2=son[u][1];
	if(v1) dt(v1);
	if(v2) dt(v2);
	if(u==1) return;
	for(LL i=0;i<=k;i++)
	  for(LL j=0;j<=k;j++)
	  {
	  	if(i+j==0) continue;
	    if(i+j+1<=k&&v1&&v2) w[u][i+j+1]=max(w[u][i+j+1],w[v1][i]+w[v2][j]+x[u]);
	  	if(i+1<=k&&v1) w[u][i+1]=max(w[v1][i]+x[u],w[u][i+1]);
	  	if(j+1<=k&&v2) w[u][j+1]=max(w[u][j+1],w[v2][j]+x[u]);
	  }
	return;
}
int main()
{
	memset(w,0xcf,sizeof(w));
	for(LL i=2;i<=n;i++) x[i]=read();
	for(LL i=1;i<=n;i++)
	{
		LL a=read(),b=read();
		son[i][0]=a;son[i][1]=b;
		if(a+b) len[i]=1;
	}
	for(LL i=2;i<=n;i++) w[i][1]=x[i],w[i][0]=0;
	dt(1);
	LL s1=son[1][0],s2=son[1][1];
	if(!s1) return !printf("%d",w[s2][k]);
	if(!s2) return !printf("%d",w[s1][k]);
	for(LL i=0;i<=k;i++)
	{
		int j=k-i;
	  	w[1][k]=max(w[1][k],w[s1][i]+w[s2][j]);
	}
	cout<<w[1][k];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值