//打赏的js文件

树形dp

树形dp

树形dp,即在树上进行的 dp。由于树固有的递归性质,树形dp 一般都是递归进行的。

例题1(洛谷 P1352 没有上司的舞会)

我以这道题为例,给大家介绍一下树形dp 的一般过程。

我们发现这道题跟每一个人去不去有很大关系。所以我们用 \(f(i,0/1)\) 表示到第 \(i\) 个人(去为 \(1\),不去为 \(0\))最大的快乐指数。于是我们可以求出每一个 \(f(i,0/1)\)

对于每一个状态(\(0\)\(1\)),我们可以按下面的方法处理。

  • 上司不参加舞会,则下属可参加可不参加,所以 \(f(i,0)=\sum\max\{f(x,0),f(x,1)\}\)
  • 上司参加舞会,则下属一定不能参加舞会,所以 \(f(i,1)=\sum f(x,0)+r_i\)

分析完后可以发现,我们可以用 \(dfs\),每次计算完 \(f(x,0)\)\(f(x,1)\) 后,立刻加入 \(f(i,0)\)\(f(i,1)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 6010;

int r[kMaxN], in[kMaxN], f[kMaxN][2], n, root;
vector<int> e[kMaxN];

void dfs(int x) {
  if (!e[x].size()) {
    f[x][1] = r[x];
    return;
  }
  for (auto i : e[x]) {
    dfs(i);
    f[x][0] += max(f[i][0], f[i][1]), f[x][1] += f[i][0];
  }
  f[x][1] += r[x];
}

int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> r[i];
  }
  for (int i = 1, u, v; i < n; i++) {
    cin >> u >> v, e[v].push_back(u), in[u]++;
  }
  for (int i = 1; i <= n; i++) {
    (!in[i]) && (root = i);
  }
  dfs(root);
  cout << max(f[root][0], f[root][1]) << '\n';
  return 0;
}
posted @ 2024-09-20 15:15  小熊涛涛  阅读(5)  评论(0编辑  收藏  举报