HDU 6201 树形dp

来源:互联网 发布:linux关机重启命令 编辑:程序博客网 时间:2024/06/11 17:18

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201
给一棵n个节点的树,每个节点和边都有权值,求一条价值最大的路径。价值为该条路径终点的价值 - 起点的价值 - 路径上边的权重和。


思路:

树形dp,分别考虑祖先与后代以及兄弟之间的关系即可。细节比较多,详见代码。


代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL INF = 0x3f3f3f3f3f3f3f3f;const int MAXN = 1e5 + 10;struct node {    int v, w;};vector <node> tree[MAXN];LL a[MAXN], dp1[MAXN], dp2[MAXN], ans;void dfs(int u, int pa) {    dp1[u] = -INF; dp2[u] = -INF;    int t1 = -1, t2 = -1;    for (int i = 0; i < (int)tree[u].size(); i++) {        int v = tree[u][i].v, w = tree[u][i].w;        if (v == pa) continue;        dfs(v, u);        if (dp1[u] < dp1[v] - w) {            t1 = i;            dp1[u] = dp1[v] - w;        }        if (dp2[u] < dp2[v] - w) {            t2 = i;            dp2[u] = dp2[v] - w;        }    }    if (t1 != -1) ans = max(ans, dp1[u] + a[u]);    if (t2 != -1) ans = max(ans, dp2[u] - a[u]);    for (int i = 0; i < (int)tree[u].size(); i++) {        int v = tree[u][i].v, w = tree[u][i].w;        if (v == pa) continue;        if (i != t1 && t1 != -1) ans = max(ans, dp1[u] + dp2[v] - w);        if (i != t2 && t2 != -1) ans = max(ans, dp2[u] + dp1[v] - w);    }    dp1[u] = max(dp1[u], -a[u]);    dp2[u] = max(dp2[u], a[u]);}int main() {    //freopen("in.txt", "r", stdin);    int T;    scanf("%d", &T);    while (T--) {        int n;        scanf("%d", &n);        for (int i = 1; i <= n; i++) {            scanf("%I64d", &a[i]);            tree[i].clear();        }        for (int i = 1; i < n; i++) {            int u, v, w;            scanf("%d%d%d", &u, &v, &w);            tree[u].push_back((node){v, w});            tree[v].push_back((node){u, w});        }        ans = -INF;        dfs(1, 0);        printf("%I64d\n", ans);    }    return 0;}