树形DP: 没有上司的舞会

c++

没有上司的舞会

/*
 * 没有上司的舞会
 * 题目描述:
 *      Ural 大学有 N 名职员,编号为 1∼N。
 *      他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。
 *      每个职员有一个快乐指数,用整数 Hi 给出,其中 1≤i≤N。
 *      现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。
 *      在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。
 * 数组含义:
 *      f[i][1] 表示用了, f[i][0] 表示没有用
 *
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>

using namespace std;

const int N = 6010;
int n;
int h[N], ne[N], e[N], idx;
int w[N];
int f[N][2];
bool st[N];

void add(int x, int y) {
    e[idx] = y, ne[idx] = h[x], h[x] = idx ++;
}

void dfs(int x) {
    int y;
    f[x][0] = 0;
    f[x][1] = w[x];
    for (int i = h[x]; ~i; i = ne[i]) {
        y = e[i];
        dfs(y);
        f[x][0] += max(f[y][0], f[y][1]);
        f[x][1] += f[y][0];
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) {
        scanf("%d", &w[i]);
    }

    idx  = 1;
    memset(h, -1, sizeof h);
    memset(ne, -1, sizeof ne);
    memset(st, false, sizeof st);

    for (int i = 1; i < n; i ++ ) {
        static int l, k;
        scanf("%d%d", &l, &k);  // k is boss
        add(k, l);
        st[l] = true;
    }

    int root = -1;

    for (int i = 1; i <= n; i ++ ) {
        if (st[i] == false) {
            root = i;
            break;  // 按道理说也是只有一个
        }
    }
    memset(f, 0, sizeof f);

//    printf("root=%d\n", root);
    dfs(root);

    printf("%d\n", max(f[root][0], f[root][1]));
    
    return 0;
}
posted @ 2022-07-08 23:03  lucky_light  阅读(35)  评论(0编辑  收藏  举报