P1352 没有上司的舞会 / 树形dp

某大学有 \(n\) 个职员,编号为 \(1\dots n\)。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 \(r_i\),但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。

所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

解法

我们设 \(dp_{(i,j)}\) 表示当前选不选择第 \(i\) 个人所能获得的最大快乐值,其中 \(j\in [0,1]\)。随后进行递归转移即可。

#include <iostream>
#include <vector>

using namespace std;

const int kMaxN = 6e3 + 5;

int a[kMaxN], d[kMaxN], dp[kMaxN][2], n, r;
vector<int> e[kMaxN];

void dfs(int x) {
  for (int i : e[x]) {
    dfs(i);  // 递归提前处理完子树
    dp[x][0] += max(dp[i][0], dp[i][1]);  // 不选当前上司
    dp[x][1] += dp[i][0];  // 选择当前上司
  }
  dp[x][1] += a[x];  // 当前上司一起跳舞
}

int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  for (int i = 1, l, k; i < n; i++) {
    cin >> l >> k;
    e[k].push_back(l);  //存边
    d[l]++;  // 入度加一
  }
  for (int i = 1; i <= n; i++) {
    if (!d[i]) {  // 找根结点
      r = i;
      break;
    }
  }
  dfs(r);
  cout << max(dp[r][0], dp[r][1]) << '\n';
  return 0;
}
posted @ 2023-10-15 16:01  haokee  阅读(19)  评论(0)    收藏  举报