题意:给出一棵树,给出每个节点的价值以及每条路径的花费,每个节点不论经过多少次只能取一次对应的价值,而每条路径每通过一次都要付出对应的代价。要求输出从每一个节点出发的最大获利。
树形dp。
思路挺显然的,但是关键是对细节的处理。先做一次dfs,预处理出每一个节点往下走不会来(v1)以及回来(v2)的最大收益。然后第二次dfs就是伴随记录每个节点往父亲走不会来(fa_v1)以及回来(fa_v2)的最大收益。那么每个节点的最大收益就是往下走回来+往上走不会来 , 或者往上走回来+往下走不会来的最大值。
主要是fa_v1 , fa_v2不太好求。假设当前是fa节点,要走到son节点。递归下去的fa_v1有两种情况:1、就是走除了son的所有fa的儿子节点然后回来,然后走fa的父亲节点然后不会来;2、就是走fa的父亲节点回来,然后走除了son节点的所有儿子节点回来并选择一条增益最大的儿子路径从从回来变成不会来(就是我程序中的max1, max2的作用)。 fa_v2就挺好算了,就是走fa的父亲以及除了son节点的所有儿子节点并且回来的最大值。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int tar[2*maxn], cost[2*maxn], nextt[2*maxn], last[maxn], tot;
int v[maxn], x, y, z, n, ans[maxn];
void insert(int x, int y, int z) {
tot++;
tar[tot] = y;
cost[tot] = z;
nextt[tot] = last[x];
last[x] = tot;
}
struct Node {
int v1, v2, max1, max2;
//v1 not return
//v2 return
}tree[maxn];
void dfs(int x, int fa) {
tree[x].v1 = tree[x].v2 = v[x];
tree[x].max1 = tree[x].max2 = 0;
int k = last[x], temp;
while (k != 0) {
if (tar[k] == fa) {
k = nextt[k]; continue;
}
dfs(tar[k], x);
tree[x].v1 = max(tree[x].v1, max(tree[x].v1+max(0, tree[tar[k]].v2-2*cost[k]), tree[x].v2+max(0, tree[tar[k]].v1-cost[k])));
tree[x].v2 = max(tree[x].v2, tree[x].v2+max(0, tree[tar[k]].v2-2*cost[k]));
temp = max(tree[tar[k]].v1-cost[k],0)-max(tree[tar[k]].v2-2*cost[k], 0);
if (temp > tree[x].max2) tree[x].max2 = temp;
if (tree[x].max2 > tree[x].max1) swap(tree[x].max1, tree[x].max2);
k = nextt[k];
}
}
void dfs2(int x, int fa, int fa_v1, int fa_v2) {
ans[x] = max(tree[x].v1+fa_v2, tree[x].v2+fa_v1);
int k = last[x], temp, tempv1, tempv2, add;
while (k != 0) {
if (tar[k] == fa) {
k = nextt[k]; continue;
}
/*v1 1*/
tempv1 = fa_v1+tree[x].v2-max(tree[tar[k]].v2-2*cost[k], 0);
/*2*/
if (max(tree[tar[k]].v1-cost[k], 0)-max(tree[tar[k]].v2-2*cost[k], 0) == tree[x].max1) add = tree[x].max2;
else add = tree[x].max1;
temp = tree[x].v2-max(tree[tar[k]].v2-2*cost[k], 0)+fa_v2+add;
tempv1 = max(tempv1, temp);
/*v2*/
tempv2 = fa_v2+tree[x].v2-max(tree[tar[k]].v2-2*cost[k], 0);
dfs2(tar[k], x, max(tempv1-cost[k], 0), max(tempv2-2*cost[k], 0));
k = nextt[k];
}
}
int main() {
freopen("hdu.in","r",stdin);
int T;
scanf("%d", &T);
for (int cases = 1; cases <= T; cases++) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
tot = 0;
memset(last, 0, sizeof(last));
for (int i = 1; i <= n-1; i++) {
scanf("%d%d%d", &x, &y, &z);
insert(x, y, z);
insert(y, x, z);
}
memset(tree, 0, sizeof(tree));
memset(ans, 0 ,sizeof(ans));
dfs(1, 0);
dfs2(1, 0, 0, 0);
printf("Case #%d:\n", cases);
for (int i = 1; i <= n; i++) printf("%d\n", ans[i]);
}
}