算法训练 结点选择

问题描述

有一棵 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的正整数。

问题分析:作为一个小白,刚拿到这个题目的时候是只想到了树,但是具体怎么实现还是一悉莫展,还好蓝桥杯网站上锦囊的提示和众多大牛的代码以及分析才能勉强写出ac代码。本题是用链式前向星的dp来实现的,真正完成后就会发现,其实本题是挺简单的(至少写出来了)。

#include<iostream>
#include<string.h> 
#include<algorithm>
using namespace std;
const int maxsize=100010;
int q[maxsize][2];
int head[maxsize];
int k=0;
struct edge
{
	int to;
	int next;
}edges[maxsize*2];
void add(int a,int b) 
{
	edges[k].to=b;
	edges[k].next=head[a];
	head[a]=k++;
	edges[k].to=a;
	edges[k].next=head[b];
	head[b]=k++;
}
void dfs(int x,int pre)//深度遍历和动态规划同步 
{
	int i=head[x];
	while(i!=-1)
	{
		int to=edges[i].to;
		if(to==pre)
		{
			i=edges[i].next;
			continue;
		}
		dfs(to,x);
		q[x][0]+=max(q[to][0],q[to][1]);
		q[x][1]+=q[to][0];
		i=edges[i].next;
	}
	/*for(int i=head[x];i!=-1;i=edges[i].next)
	{
		int to=edges[i].to;
		if(to==pre)
		continue;
		dfs(to,x);
		q[x][1]+=q[to][0];
		q[x][0]+=max(q[to][0],q[to][1]);
	}*/
}
int main()
{
	int n;
	cin>>n;
	memset(head,-1,sizeof(head));
	memset(q,0,sizeof(q));
	for(int i=1;i<=n;i++)
	cin>>q[i][1];
	for(int i=1;i<=n-1;i++)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
	}
	dfs(1,-1);
	cout<<max(q[1][0],q[1][1]);
	return 0;
}

本人比较懒,直接将ac的代码复制上来了,也没有过多的加注释,如果有看不懂的朋友,欢迎留言评论。。。。。。

猜你喜欢

转载自blog.csdn.net/weixin_43841676/article/details/86096422