【洛谷】P1352 没有上司的舞会

题目地址:

https://www.luogu.com.cn/problem/P1352

某大学有 n n n个职员,编号为 1 ∼ n 1\sim n 1n。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r i r_i ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

输入格式:
输入的第一行是一个整数 n n n
2 2 2到第 ( n + 1 ) (n + 1) (n+1)行,每行一个整数,第 ( i + 1 ) (i+1) (i+1)行的整数表示 i i i号职员的快乐指数 r i r_i ri
( n + 2 ) (n + 2) (n+2)到第 2 n 2n 2n行,每行输入一对整数 l , k l, k l,k,代表 k k k l l l的直接上司。

输出格式:
输出一行一个整数代表最大的快乐指数。

数据范围:
对于 100 % 100\% 100%的数据,保证 1 ≤ n ≤ 6 × 1 0 3 1\leq n \leq 6 \times 10^3 1n6×103 − 128 ≤ r i ≤ 127 -128 \leq r_i\leq 127 128ri127 1 ≤ l , k ≤ n 1 \leq l, k \leq n 1l,kn,且给出的关系一定是一棵树。

所有点形成一个森林,设 f [ v ] [ 0 ] f[v][0] f[v][0]表示 v v v为根的子树如果 v v v不参加舞会,能得到的最大快乐指数, f [ v ] [ 1 ] f[v][1] f[v][1]表示 v v v为根的子树如果 v v v参加舞会,能得到的最大快乐指数。那么在计算 f [ v ] f[v] f[v]的时候,可以先递归计算其所有孩子的 f f f值,然后考虑 f [ v ] f[v] f[v],对于 f [ v ] [ 0 ] f[v][0] f[v][0],由于 v v v没参加,所以其子树树根可以参加也可以不参加,所以 f [ v ] [ 0 ] = ∑ v → u max ⁡ { f [ u ] [ 0 ] , f [ u ] [ 1 ] } f[v][0]=\sum_{v\to u} \max\{f[u][0],f[u][1]\} f[v][0]=vumax{f[u][0],f[u][1]}对于 f [ v ] [ 1 ] f[v][1] f[v][1],由于 v v v参加了,所以其所有子树树根都不能参加,所以 f [ v ] [ 1 ] = ∑ v → u f [ u ] [ 0 ] f[v][1]=\sum_{v\to u}f[u][0] f[v][1]=vuf[u][0]最后对于所有树根 v i v_i vi,求一下 ∑ i max ⁡ { f [ v i ] [ 0 ] , f [ v i ] [ 1 ] } \sum_i \max\{f[v_i][0],f[v_i][1]\} imax{f[vi][0],f[vi][1]}即为答案。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

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

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

void dfs(int u) {
  f[u][1] = r[u];
  for (int i = h[u]; ~i; i = ne[i]) {
    int v = e[i];
    dfs(v);
    f[u][1] += f[v][0];
    f[u][0] += max(f[v][0], f[v][1]);
  }
}

int main() {
  memset(h, -1, sizeof h);
  fill(is_boss, is_boss + N, true);

  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d", &r[i]);
  for (int i = 1; i <= n - 1; i++) {
    int a, b;
    scanf("%d%d", &a, &b);
    add(b, a);
    is_boss[a] = false;
  }

  int res = 0;
  for (int i = 1; i <= n; i++)
    if (is_boss[i]) {
      dfs(i);
      res += max(f[i][0], f[i][1]);
    }

  printf("%d\n", res);
}

时空复杂度 O ( n ) O(n) O(n)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值