(蓝桥杯 算法题)节点选择

问题描述

有一棵 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.	///邻接表构建过程  
2.	#include <iostream>  
3.	#include <cstdio>  
4.	#include <cstring>  
5.	#include <algorithm>  
6.	#include <vector>  
7.	using namespace std;  
8.	typedef long long LL;  
9.	  
10.	struct Edge{  
11.	    int edge;  
12.	    int next;  
13.	}e[300000];  
14.	  
15.	int head[300000],val[300000];  
16.	int N,M;  
17.	LL dp[150000][2]; ///dp[s/u][0/1],u为s的子节点,0表示包含自己的以s为根节点的子树最大值,1表示不包含自己的以s为根节点的子树最大值  
18.	bool v[150000];  
19.	  
20.	void add(int s,int ee)  
21.	{  
22.	    e[++M].edge = ee;           ///边的终点  
23.	    e[M].next = head[s];        ///邻边  
24.	    head[s] = M;                ///当前边  
25.	}  
26.	  
27.	void dfs(int s)  
28.	{  
29.	    dp[s][0]=val[s];  
30.	    dp[s][1]=0;  
31.	    for(int i=head[s];i!=-1;i=e[i].next)  
32.	    {  
33.	        int u=e[i].edge;  
34.	        if(v[u]==0)  
35.	        {  
36.	            v[u]=1;  
37.	            dfs(u);  
38.	            dp[s][0]+=dp[u][1];  
39.	            dp[s][1]+=max(dp[u][1],dp[u][0]);  
40.	            v[u]=0;  
41.	        }  
42.	    }  
43.	  
44.	}  
45.	  
46.	int main()  
47.	{  
48.	    int s,e;  
49.	    int ans=0;  
50.	    memset(head,-1,sizeof(head));  
51.	    memset(dp,0,sizeof(dp));  
52.	    memset(v,0,sizeof(v));  
53.	    cin>>N;  
54.	    for(int i=1;i<=N;i++)  
55.	        cin>>val[i];  
56.	    for(int i=1;i<N;i++)  
57.	    {  
58.	        cin>>s>>e;  
59.	        add(s,e);  
60.	        add(e,s);  
61.	    }  
62.	    v[1]=1;  
63.	    dfs(1);  
64.	    v[1]=0;  
65.	    ans=max(dp[1][0],dp[1][1]);  
66.	    cout<<ans<<endl;  
67.	    return 0;  
68.	}  

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值