标签:
题目大意:给出一棵树,每条边都有一个权值,要求求出从每个点出发的最大权值和
解题思路:无根树先转化成有根树,以1为根
先dfs一次,求出以某个点为根,通过子节点所能到得到的最大权值和,和次大权值和,并纪录求得最大权值和的那个子节点
这样我们只考虑了通过子节点得到最大权值和的情况,但要求最大权值和,当然还要判断通过父节点得到最大权值和是否会大于通过子节点得到最大权值和,怎么判断呢?
设dp[i]为i节点通过父节点得到的最大权值和
那么分两种情况讨论
1.子节点是求得最大权值和的那个节点
那么dp[son] = max(dp[fa], er[fa]) + w[fa][son]
2.子节点不是求得最大权值和的那个节点
dp[son] = max(dp[fa], est[fa]) + w[fa][son]
PS:son表示子节点,fa表示父节点,est[fa]表示的以fa为根,然后通过子节点得到的最大权值和,er[fa]表示的是以fa为根,然后通过子节点得到的次大权值和,w[fa][son]指的是父节点和子节点之间的权值
具体的可以画图看一下就知道了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 10010
vector<int> Node[maxn], w[maxn];
int dp[maxn], mark[maxn], est[maxn], er[maxn];
int n;
int dfs(int cur) {
if(est[cur])
return est[cur];
int size = Node[cur].size();
if(size == 0)
return 0;
int Est = -1, Esi = -1, Er = -1, Eri = -1;
for(int i = 0; i < size; i++) {
if( dfs(Node[cur][i]) + w[cur][i] > Est) {
Esi = i;
Est = est[Node[cur][i]] + w[cur][i];
}
}
est[cur] = Est;
mark[cur] = Esi;
for(int i = 0; i < size; i++)
if(est[Node[cur][i]] + w[cur][i] > Er && (i != Esi)) {
Er = est[Node[cur][i]] + w[cur][i];
Eri = i;
}
if(Eri != -1)
er[cur] = Er;
return est[cur];
}
void dfs2(int cur) {
int size = Node[cur].size();
for(int i = 0; i < size; i++) {
if(i == mark[cur])
dp[Node[cur][i]] = max(er[cur], dp[cur]) + w[cur][i];
else
dp[Node[cur][i]] = max(est[cur], dp[cur]) + w[cur][i];
dfs2(Node[cur][i]);
}
}
void init() {
for(int i = 1; i <= n; i++) {
Node[i].clear();
w[i].clear();
est[i] = er[i] = 0;
}
int x, y;
for(int i = 2; i <= n; i++) {
scanf("%d%d", &x, &y);
Node[x].push_back(i);
w[x].push_back(y);
}
}
int main() {
while(scanf("%d", &n) != EOF) {
init();
dfs(1);
dp[1] = 0;
dfs2(1);
for(int i = 1; i <= n; i++)
printf("%d\n", max(est[i], dp[i]));
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/l123012013048/article/details/45743569