问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 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的正整数。
代码如下:
#include "stdio.h"
#define MAX 100010
#define max(a,b) a>b?a:b
struct tnode
{
int son[2];
int indegree;
}tnode[MAX];
void DFS(int x,int dp[MAX][2],int weight[MAX]);
int main()
{
int n,i,a,b,root;
int weight[MAX]={0},dp[MAX][2]={0};
scanf("%d",&n);
for(i=1;i<=n;i++)//初始化树节点
{
scanf("%d",&weight[i]);
tnode[i].son[0]=-1;
tnode[i].son[1]=-1;
tnode[i].indegree=0;
}
for(i=0;i<n-1;i++)//建树
{
scanf("%d%d",&a,&b);
if(tnode[a].son[0] == -1)
tnode[a].son[0] = b;
else
tnode[a].son[1] = b;
tnode[b].indegree++;
}
for(i=1;i<=n;i++)//寻找根节点
if(! tnode[i].indegree)
root=i;
DFS(root,dp,weight);//利用dfs原理
printf("%d\n",max(dp[root][0],dp[root][1]));
return 0;
}
void DFS(int x,int dp[MAX][2],int weight[MAX])
{
int i,son;
dp[x][1]=weight[x];
for(i=0;i<2;i++)
{
son=tnode[x].son[i];
if(son == -1)
continue;
DFS(son,dp,weight);
dp[x][0]+=max(dp[son][1],dp[son][0]);
dp[x][1]+=dp[son][0];
}
}
dp[x][0]不取该结点的最大值 dp[x][1]取该结点的最大值
根据题目中,对于每一个结点都存在两种取与不取
1.取结点x,dp[x][1]=weight[x];
那么对其孩子结点只能不取这一种情况dp[x][1]+=dp[son][0];
2.如果不取结点x,对于孩子结点有两种选择就是(取dp[son][1]与不取dp[son][0],当dp[x][0]加上肯定是两者之间最大值)
dp[x][0] += max ( dp[son][0] , dp[son][1]) ;