洛谷 P1352 没有上司的舞会

题目链接:没有上司的舞会



思路

       这是一道树形dp的入门题,也可以用DFS+记忆化搜索来理解,要注意的地方是,输入关系时先输入的l为后输入的k的下属,所以存储边时需要注意。

       在面对图论或者树的存储时通常可以使用链式向前星(如下代码中的add函数)或者STL中的vector存储边。
       链式向前星和vector数组存储的差别在于,链式向前星的时间效率会比vector数组要高,而且vector数组存储边时的空间消耗可能也会比链式向前星要高,因为vector每次扩充容量时默认是申请当前容量的1.5倍或者2倍,所以可能在面对一些题目时会浪费很多的空间,被卡内存,所以在面对知道边数的题目时,尽量使用链式向前星会节省时间和空间效率。

       使用happy数组存储每个员工的快乐指数,subordinate数组标记当前元素是否是下属,因为题目没给出根节点是哪个节点,所以需要自己找出根节点,由于给出的数据结构是一颗树只有一个根节点,所以可以逐个标记下属subordinate[i] = true,最后没有被标记的节点subordinate[i] == false就是根节点。
       dp数组存储的是当前节点及其子树最大的快乐指数,dp[i][0]表示不邀请职员i时,职员i及其所有直接和间接下属能得到的最大的快乐指数,dp[i][1]表示邀请职员i时,职员i及其所有直接和间接下属能得到的最大的快乐指数。
       搜索中要求出dp[i][0]和dp[i][1]需要先得到下属对应子树的最大快乐指数,所以需要先dfs在加上下属对应子树的最大快乐指数。


题解

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 10;

int dp[N][2], happy[N], subordinate[N], cnt, head[N], nex[N], edge[N];
// 链式向前星存储边
void add(int x, int y) {
  nex[++cnt] = head[x];
  head[x] = cnt;
  edge[cnt] = y;
}

// 树形dp
void dfs(int x) {
	dp[x][0] = 0;
	dp[x][1] = happy[x];
	for (int i = head[x]; i; i = nex[i]) {
		int to = edge[i];
		dfs(to);
		dp[to][1] += dp[to][0];
		dp[to][0] += max(dp[to][0], dp[to][1]);
	}
}

int main() {
  int n, l, k;

  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> happy[i];
  }
  for (int i = 1; i < n; i++) {
    cin >> l >> k;
    add(k, l);
    subordinate[l] = true;
  }

  int root;
  for (int i = 1; i <= n; i++) {
    if (subordinate[i] == false) {
      root = i;
      break;
    }
  }

  dfs(root);
  cout << max(dp[root][0], dp[root][1]);

	return 0;
}
posted @ 2024-06-13 11:06  薛定谔的AC  阅读(17)  评论(0编辑  收藏  举报