• 树形dp练习


    洛谷P1352 没有上司的舞会

    经典的树形dp

    f[x][0]表示以x为根的子树,且x不参加舞会的最大快乐值

    f[x][1]表示以x为根的子树,且x参加了舞会的最大快乐值

    则f[x][0]=sigma{max(f[y][0],f[y][1])} (y是x的儿子)

    f[x][1]=sigma{f[y][0]}+h[x] (y是x的儿子)

    先找到唯一的树根root

    则ans = max(f[root][0], f[root][1])

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 6e3 + 7;
    struct edge
    {
        int to, next;
    }e[maxn];
    int r[maxn], head[maxn], cnt, f[maxn][2];
    bool mark[maxn], vis[maxn];
    
    void add(int u, int v)
    {
        e[++cnt].next = head[u];
        e[cnt].to = v;
        head[u] = cnt;
    }
    
    void dfs(int x)
    {
        vis[x] = 1;
        if(!head[x]) //x为叶子结点
        {
            f[x][0] = 0;
            f[x][1] = r[x]; //所以可以简化为无需r数组,开始直接读入f[x][1],这样最后也不用+=r[x]了
            return;
        }
        for(int i = head[x]; i; i = e[i].next)  //遍历以x为起点的所有边
        {
            int y = e[i].to;
            if(vis[y]) continue;
            dfs(y);   //在下两行使用y前,保证y已经计算出来
            f[x][0] += max(f[y][0], f[y][1]);
            f[x][1] += f[y][0];
        }
        f[x][1] += r[x];
        return;
    }
    
    int main()
    {
        int n, a, b;
        cin >> n;
        for(int i = 1; i <= n; ++i) scanf("%d", &r[i]);
        for(int i = 1; i <= n - 1; ++i)
        {
            scanf("%d %d", &a, &b);
            add(b, a);  //加边是单向的,a是b的父亲,b不是a的父亲
            mark[a] = 1;
        }
        for(int i = 1; i <= n; ++i)
        {
            if(!mark[i])  //找到根
            {
                dfs(i);
                printf("%d
    ", max(f[i][0], f[i][1]));
                return 0;
            }
        }
    }
  • 相关阅读:
    xt
    UVA 10200 Prime Time (打表)
    CodeForces 540B School Marks
    CodeForces 540C Ice Cave (BFS)
    poj 3250 Bad Hair Day(栈的运用)
    hdu A Magic Lamp
    hdu 4325 Flowers(区间离散化)
    hdu 5500 Reorder the Books
    V2X之标准
    V2X的前生今世
  • 原文地址:https://www.cnblogs.com/Maxx-el/p/14178475.html
Copyright © 2020-2023  润新知