前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >算法训练 结点选择

算法训练 结点选择

作者头像
刘开心_1266679
发布2019-02-14 15:23:15
7090
发布2019-02-14 15:23:15
举报

问题描述

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

输入格式

第一行包含一个整数 n 。

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。

接下来一共 n-1 行,每行描述树上的一条边。

输出格式

输出一个整数,代表选出的点的权值和的最大值。

样例输入

5 1 2 3 4 5 1 2 1 3 2 4 2 5

样例输出

12

样例说明

选择3、4、5号点,权值和为 3+4+5 = 12 。

数据规模与约定

对于20%的数据, n <= 20。

对于50%的数据, n <= 1000。

对于100%的数据, n <= 100000。

权值均为不超过1000的正整数。

思路:

       树形动态规划问题最重要的两步首先是建树,然后是进行动态规划。

     (1)这是一棵无根多叉树,可以采用邻接表法存储,为了避免指针的使用麻烦,采用数组来代替,用head[maxn]存储头结点编号,用list[2*manx].vex存放邻接点域,用list[2*maxn].next存放链域。

     (2)由于无根,所以哪个节点都能当做根,用y[i]表示选择第i个根的权值和,用n[i]表示不选择第i个根的权值和,假设选择了第i个根,则不能选择它的孩子,假如不选择第i个根,则它的孩子可选可不选(即可以选择孩子也可以选择孙子)。

代码语言:javascript
复制
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 5;
int m, cnt = 0;
int y[maxn] = {0}, n[maxn] = {0}, w[maxn], head[maxn] = {0}, vis[maxn] = {0}; 

struct ArcNode
{
	int vex, next;
}list[2 * maxn];

//插入边,插成对称的 

void Insert(int u, int v)
{
	list[++cnt].vex = v;
	list[cnt].next = head[u];
	head[u] = cnt;
	list[++cnt].vex = u;
	list[cnt].next = head[v];
	head[v] = cnt;
}

void Dp(int root)
{
	vis[root] = 1;
	for(int i = head[root]; i != 0; i = list[i].next)
	{
		if(vis[list[i].vex] == 0)
		{
			Dp(list[i].vex);
			y[root] += n[list[i].vex];
			n[root] += max(y[list[i].vex], n[list[i].vex]);
		}
	}
	y[root] += w[root];
}

int main()
{
	int i, j, u, v, ans;
	scanf("%d", &m);
	for(i = 1; i <= m; i++)
		scanf("%d", &w[i]);
	for(j = 1; j <= m - 1; j++)
	{
		scanf("%d%d", &u, &v);
		Insert(u, v); 
	}
	Dp(1);
	ans = max(y[1], n[1]);
	printf("%d\n", ans);
	return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年03月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档