Zoj3201 Tree of Tree 树形DP

来源:互联网 发布:软件业务需求分析 编辑:程序博客网 时间:2024/05/17 04:42

题目大意:从一棵树上选取k个节点的子树使节点权值之和最大

思路: 想到是树形DP了但是一直推不出来状态状态转移方程,首先是自己状态如何表示都没想好

刚开始时用状态f[u][k][0]和f[u][k][1]表示以节点u父亲节点选k个节点0表示不选u,1表示选u,如果选u的话u的儿子至少要选一个,不选的话儿子可选可不选,

然后想想这样下边计算时就会越来越乱~~~

然后看了别人的思路:f[u][k]表示以u为根选k个节点的最大值,最后把所有的节点扫一遍就找到最大值了,真是简化了好多,实现时要用到01背包的思想,因为对于u的每个儿子,可以选择分 1,2,3…k-1 个节点给它


#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<vector>using namespace std;const int maxn = 105;const int INF = 0x7f7f7f7f;int num[maxn];int vis[maxn], f[maxn][maxn], head[maxn];int tot;struct Eage{    int to, next;} eage[maxn*2];int n, m;inline void add(int x, int y){    eage[tot].to = y;    eage[tot].next = head[x];    head[x] = tot++;}void dfs(int x){    vis[x] = 1;    f[x][1] = num[x];    for (int i = head[x]; i !=-1 ; i = eage[i].next)    {        int v = eage[i].to;        if (!vis[v])        {            dfs(v);            for (int k = m; k >= 1; k--)            {                for (int j = 0; j < k; j++)//j从0到k-1                {                    f[x][k] = max(f[x][k], f[x][k-j]+f[v][j]);                }            }        }    }}int main(){    //freopen("input.txt", "r", stdin);    while (cin >> n >> m)    {        tot = 0;        memset(f, 0, sizeof(f));        memset(head, -1, sizeof(head));        memset(eage, 0, sizeof(eage));        memset(vis, 0, sizeof(vis));        for (int i = 0; i < n; i++) scanf("%d", num+i);        int x, y;        for (int i = 1; i < n; i++)        {            scanf("%d%d", &x, &y);            add(x, y);            add(y, x);        }        dfs(0);        int ans = 0;        for (int i = 0; i < n; i++)            if (ans < f[i][m]) ans = f[i][m];        cout << ans << endl;    }    return 0;}



0 0
原创粉丝点击