HDU5242(树DP)

来源:互联网 发布:c语言中的头文件是 编辑:程序博客网 时间:2024/05/26 02:20

题意是取k个点,每次累加从根到这个点的权值的和,最多只能加一次,问最大能得到多少。

用sum[i]表示i到叶子节点的最大的路径上的和,son[i]表示和最大的路径上的i的孩子,father[i]表示和最大的路径上的i的父亲。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <iostream>using namespace std;#define maxn 111111struct node {    int from, to, next;}edge[maxn*2];int head[maxn], cnt;long long sum[maxn], a[maxn];int n, k, t, father[maxn], son[maxn];long long ans[maxn];int ans_cnt;void add_edge (int from, int to, int i) {    node &e = edge[i];    e.from = from, e.to = to, e.next = head[from], head[from] = i;}void dfs (int u, int fa) {    for (int i = head[u]; i != -1; i = edge[i].next) {        int v = edge[i].to;        if (v == fa)            continue;        dfs (v, u);        if (sum[v] > sum[u]) {            son[u] = v;            sum[u] = sum[v];        }    }    father[son[u]] = u;    sum[u] += a[u];    return ;}int main () {    //freopen ("in", "r", stdin);    scanf ("%d", &t);    int kase = 0;    while (t--) {        scanf ("%d%d", &n, &k);        int u, v;        for (int i = 1; i <= n; i++) {            scanf ("%lld", &a[i]);        }        cnt = 0;        memset (head, -1, sizeof (head));        for (int i = 1; i < n; i++) {            scanf ("%d%d", &u, &v);            add_edge (u, v, cnt++);            add_edge (v, u, cnt++);        }        memset (sum, 0, sizeof sum);        memset (father, -1, sizeof father);        memset (son, -1, sizeof son);        dfs (1, 0);        ans_cnt = 0;        for (int i = 1; i <= n; i++) {            if (father[i] == -1) {                ans[ans_cnt++] = sum[i];            }        }        sort (ans, ans+ans_cnt);        long long gg = 0;        for (int i = 1, j = ans_cnt-1; i <= min (ans_cnt, k); i++, j--)            gg += ans[j];        printf ("Case #%d: %lld\n", ++kase, gg);    }    return 0;}


0 0