ZOJ - 3201 Tree of Tree

题目大意:给一棵节点带权的树,找到一个有k个节点的子树,求这个子树的最大权值

解题思路:树形 DP + 背包,f(i, j) 表示以i为根节点的有j个节点子树的最大权值,然后对i的每个子节点做分组背包,因为对于i的每个儿子,可以选择分 1,2,3…j-1 个节点给它

f(i, j) = max{ max{f(i, j-p) + f(v, p) | 1 <= p < j} | v是i的儿子节点}
 ans = max{ f[i][k] | 0 <= i < n && i子树节点个数>=k }


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int N, K, ans, DP[105][105], vis[105];
vector <int> A[105];

void init() {
    ans = 0;
    memset(DP, 0, sizeof(DP));
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i <= N; i++)
        A[i].clear();

    for (int i = 0; i < N; i++)
        scanf("%d", &DP[i][1]);

    int x, y;
    for (int i = 0; i < N - 1; i++) {
        scanf("%d%d", &x, &y);
        A[x].push_back(y);
        A[y].push_back(x);
    }
}

void DPS(int root) {
    vis[root] = 1;
    int num = A[root].size();
    for (int i = 0; i < num; i++) {
        int child = A[root][i];
        if (vis[child])
            continue;
        DPS(child);
        for (int j = K; j > 0; j--)
            for (int r = 1; r < j; r++)
                DP[root][j] = max(DP[root][j], DP[root][j - r] + DP[child][r]);
    }
    ans = max(ans, DP[root][K]);
}

int main() {
    while (scanf("%d%d", &N, &K) != EOF) {
        init();
        DPS(0);
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(ZOJ - 3201 Tree of Tree)