Week13—苹果树

问题描述

在大家的三连助攻下,TT 一举获得了超级多的猫咪,因此决定开一间猫咖,将快乐与大家一同分享。并且在开业的那一天,为了纪念这个日子,TT 在猫咖门口种了一棵苹果树。

一年后,苹果熟了,到了该摘苹果的日子了。

已知树上共有 N 个节点,每个节点对应一个快乐值为 w[i] 的苹果,为了可持续发展,TT 要求摘了某个苹果后,不能摘它父节点处的苹果。

TT 想要令快乐值总和尽可能地大,你们能帮帮他吗?
【输入】
结点按 1~N 编号。

第一行为 N (1 ≤ N ≤ 6000) ,代表结点个数。

接下来 N 行分别代表每个结点上苹果的快乐值 w[i](-128 ≤ w[i] ≤ 127)。

接下来 N-1 行,每行两个数 L K,代表 K 是 L 的一个父节点。

输入有多组,以 0 0 结束。
【输出】
每组数据输出一个整数,代表所选苹果快乐值总和的最大值。
【输入样例】

7
1
1
1
1
1
1
1
1 3
7 4
2 3
4 5
6 4
3 5
0 0

【输出样例】

5

问题分析

首先存储苹果树结构,选择链式前向星,本题与上司跳舞完全相同,我们将每个节点分成两种情况,dp[1][node]是选了当前子树根节点的最大值,dp[0][node]是没选当前子树根节点的最大值
如果选择dp[1][node],那么这个节点的孩子就不可以被选择,dp[1][node]=Σdp[0][kid],如果不选择node节点,那么任意一个孩子节点都可以被选择,每个孩子节点选那个最大的,把所有孩子结点的累加起来,并且加上本来根节点的权重
状态转移方程为:
dp[1][p]+=dp[0][kid];
dp[0][p]+=max(dp[0][kid],dp[1][kid]);

代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int nmax=6e3+10;
int head[nmax],tot=1;
int w[nmax],p[nmax],dp[2][nmax];//dp[1][]选中,dp[0][]没有

struct edge
{
	int to,parent,next;
}edges[nmax];

void add(int parent,int kid)
{
	p[kid]=parent;//父节点 
	edges[++tot].to=kid;
	edges[tot].parent=parent;
	edges[tot].next=head[parent];
	head[parent]=tot;
}
void solve(int p)
{
	for(int i=head[p];i;i=edges[i].next)
	{
		int kid=edges[i].to;
		solve(kid);
		dp[1][p]+=dp[0][kid];
		dp[0][p]+=max(dp[0][kid],dp[1][kid]);
	}
	dp[1][p]+=w[p];
}
int main(){
	int N,L,K;
	while(cin>>N){
		if(N==0) break;
		memset(head,0,sizeof(head));
		memset(dp,0,sizeof(dp));
		memset(p,0,sizeof(p));
		tot=1;
		for(int i=1;i<=N;i++)
			cin>>w[i];
		for(int i=1;i<N;i++)
		{
			cin>>L>>K;
			add(K,L);
		}
		//找到根
		int root=1;
		while(p[root])
			root=p[root];
		solve(root);
		int ans=max(dp[0][root],dp[1][root]);
		cout<<ans<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值