hdu1520 Anniversary party---树形dp(用邻接表建树 + dfs记忆化搜索)

题目大意:一颗有根树上每个根结点有一个权值,相邻的父结点和子结点只能选择一个,问如何选择,使得总权值之和最大。(邀请员工参加宴会,为了避免员工和直属上司发生尴尬,规定员工和直属上司不能同时出席。)

输入:结点编号从1到N。输入的第一行包含数字N。1<= N <= 6000。随后的N行中的每一行都包含结点的权值。范围是一个介于-128到127之间的整数。下面是T行,描述一个父子关系,每一行都有如下形式:

L K
第K个结点是第L个结点的父结点。读到0 0时结束。

输出:输出总的最大权值。

输入样例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

输出样例:
5

 


 

解题代码

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 6000 + 10; //dp[i][0]表示不选择当前结点i时的最优解 
int value[maxn], dp[maxn][2], father[maxn], n; //dp[i][1]表示选择当前结点i时的最优解 
vector<int>	tree[maxn]; //用邻接表建树 

void dfs(int u) {
	dp[u][0] = 0; //赋初值:不参加宴会
	dp[u][1] = value[u]; //赋初值:参加宴会
	for(int i = 0; i < tree[u].size(); i++) { //逐一处理这个父结点的每个子结点
		int son = tree[u][i];
		dfs(son); //深搜子结点
		dp[u][0] += max(dp[son][1], dp[son][0]); //父结点不选,子结点可选可不选,并继承两者中的最大值
		dp[u][1] += dp[son][0]; //父结点选择,子结点不能选择
	}
}

int main()
{
	while (~scanf("%d",&n)) { //当读完时,scanf返回EOF(即-1,然后-1的二进制码各个位上全是1),按位取反后-1会变成0
		for(int i = 1; i <= n; i++) { 
			scanf("%d",&value[i]);
			tree[i].clear(); //赋初值,还没建立关系
			father[i] = -1;
		}
		
		while (1) {
			int t1, t2;
			scanf("%d %d",&t1,&t2);
			if (t1 == 0 && t2 == 0) break;
			tree[t2].push_back(t1); //用邻接表建树
			father[t1] = t2;
		}
		
		int root = 1;
		while (father[root] != -1) { //查找树的根结点
			root = father[root];
		}
		dfs(root); //从根结点开始,用DFS遍历整棵树 
		printf("%d\n", max(dp[root][1], dp[root][0])); 
	}
	
	return 0;
}
		

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重剑DS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值