ZOJ - 3201 Tree of Tree 树形DP

来源:互联网 发布:windows10装机必备软件 编辑:程序博客网 时间:2024/05/17 07:53

题目大意:给出一棵N个点的无根树,每个节点都有对应的值
现要求你找出一棵K个节点的子树,使得这棵子树上的值的和最大

解题思路:无根树先化为有根树,以0为根
K个节点的子树,K个节点里面的任意一个节点都可以为根,所以就不用考虑哪个节点是这棵子树的根的问题了,只需要由根0向下递归寻找就可以了
用dp[i][j]表示以i为根节点且节点数为j的树的和的最大值
那么dp[i][j] = max(dp[i][j], dp[i][j-k] + dp[son][k]) son是i的子节点

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define maxn 110vector<int> Node[maxn];int w[maxn], dp[maxn][maxn], son[maxn];int n, k, ans;int dfs(int cur, int fa) {    int size = Node[cur].size();    son[cur] = 1;    for(int i = 0; i < size; i++) {         if(Node[cur][i] != fa) {             son[cur] += dfs(Node[cur][i], cur);        }    }    dp[cur][1] = w[cur];    for(int i = 0; i < size; i++) {        int u = Node[cur][i];        if(u == fa)            continue;        for(int j = son[cur]; j >= 1; j--)            for(int l = 0; l < j && l <= son[u]; l++)                dp[cur][j] = max(dp[cur][j], dp[cur][j-l] + dp[u][l]);    }    if(dp[cur][k] > ans)        ans = dp[cur][k];    return son[cur];}int main() {    while(scanf("%d%d", &n, &k) != EOF) {        for(int i = 0; i < n; i++) {            Node[i].clear();            scanf("%d", &w[i]);        }        int x, y;        for(int i = 0; i < n - 1; i++) {            scanf("%d%d", &x, &y);            Node[x].push_back(y);            Node[y].push_back(x);        }        ans = 0;        memset(dp,0,sizeof(dp));        dfs(0,-1);        printf("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击