转自
http://blog.csdn.net/f_zyj/article/details/50823600
题目:
问题描述
有一棵 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 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
看过这道题,我们大概可以知道,这是一道和树有关的问题,那么我们需要考虑的就是如何去遍历树?很明显,我们需要用到DFS。仔细读这道题,然后我们就可以得到这还需要用到动态规划,由此,我们做这道题,解题方案也就是树形动态规划了!
既然要用动态规划,构造状态转移方程是必不可少了! 对于叶子结点: dp[k][0] = 0; dp[k][1] = k点权值; 对于非叶子结点: dp[i][0] = max(dp[j][0], dp[j][1]); (j是i的儿子) dp[i][1] = i点权值 + dp[j][0]; (j是i的儿子) 最大权值即为: max(dp[0][0], dp[0][1])。(要么不包括根结点,要么包括根结点)
代码如下:
#include <stdio.h>
#include <string.h>
#define _Max 100010
#define max(a, b) a > b ? a : b
struct point
{
int v, next;
} edge[_Max * 2 ];
int head[_Max];
int M;
int dp[_Max][2 ];
void addEdge(int from, int to)
{
edge[M].v = to;
edge[M].next = head[from];
head[from] = M++;
edge[M].v = from;
edge[M].next = head[to];
head[to] = M++;
return ;
}
void dfs(int x, int pre)
{
int i = head[x], v;
for (; i != -1 ; i = edge[i].next)
{
v = edge[i].v;
if (pre == v)
{
continue ;
}
dfs(v, x);
dp[x][1 ] += dp[v][0 ];
dp[x][0 ] += max(dp[v][0 ], dp[v][1 ]);
}
return ;
}
int main(int argc, const char * argv[])
{
int i, n, s, t, tmp;
scanf ("%d" , &n);
M = 0 ;
memset (head, -1 , sizeof (head));
memset (dp, 0 , sizeof (dp));
for (i = 1 ; i <= n; i++)
{
scanf ("%d" , &dp[i][1 ]);
}
for (i = 1 ; i < n; i++)
{
scanf ("%d %d" , &s, &t);
addEdge(s, t);
}
dfs(1 , -1 );
tmp = max(dp[1 ][0 ], dp[1 ][1 ]);
printf ("%d\n" , tmp);
return 0 ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
具体的思路实现都注释了,希望可以帮助理解。 OVER!!!