P1352「没有上司的舞会」

2022-03-02 20:13:53 浏览数 (2)

1. 题目

题目链接:P1352「没有上司的舞会」 。

题目描述

某大学有 n 个职员,编号为 1 ldots n

他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

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

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

输入格式

输入的第一行是一个整数 n

第 2 到第 (n 1) 行,每行一个整数,第(i 1)行的整数表示 i号职员的快乐指数r_i

(n 2)到第 2n 行,每行输入一对整数 l, k,代表 k l的直接上司。

输出格式

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

输入输出样例

输入 #1
代码语言:javascript复制
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出 #1
代码语言:javascript复制
5

2. 题解

分析

这是一道简单的树上 dp问题:

  • 首先构造状态 f[i][0/1] 表示以结点 i 为根的子树的最优解(第二维 0 表示 i 不参加舞会,1 表示 i参加舞会)。
  • 然后构造状态转移方程:
  1. 上司不参加舞会时,下属可参加可不参加: f[i][0] = sum max{f[x][1], f[x][0]}
  2. 上司参加舞会时,下属都不会参加: f[i][1] = sum f[x][0] a_i

然后具体实现计算时:

  • 可以采用 DFS 遍历整棵树,在返回上一层时更新当前结点的最优解。
  • 或者可以利用树的性质,即每个非根结点有且仅有一个父结点,因此可以先计算所有子树的最优解,再往上更新父结点。最开始先计算所有叶结点,即没有孩子结点的点,我们可以把孩子结点到父结点的边看作时父结点的入边,则叶结点就是入度为 0 的点,从而得到计算的结点的顺序即为结点拓扑排序的顺序。

代码

代码语言:javascript复制
#include <bits/stdc  .h>
#define ll int 
#define MAXN 6005
using namespace std;

// 前向星存边
ll cnt;
ll head[MAXN];
struct edge{
    ll to;
    ll next;
} e[MAXN];
void init(ll n) {
    cnt = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(ll u, ll v) {
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt  ;
}

ll in[MAXN];        // 入度
ll parent[MAXN];    // 父结点
ll dp[MAXN][2];     

int main()
{
    ll n;
    ll a[MAXN];
    scanf("%d", &n);
    for(ll i = 1; i <= n;   i) {
        scanf("%d", a i);
    }
    ll u, v;
    init(n);
    for(ll i = 0; i < n-1;   i) {
        scanf("%d%d", &u, &v);
        parent[u] = v;  // 记录结点的父结点
        addEdge(v, u);  // 前向星存父结点到孩子结点的边
          in[v];        // 记录结点的度
    }
    // 构造拓扑序列
    // 同时沿着拓扑序列更新结点的最优解
    queue <ll> q;
    for(ll i = 1; i <= n;   i) {
        if(!in[i]) {
            dp[i][1] = a[i];
            --in[parent[i]];
            if(!in[parent[i]]) {
                q.push(parent[i]);
            }
        }
    }
    while(q.size()) {
        u = q.front();
        q.pop();
        --in[parent[u]];
        if(!in[parent[u]])  q.push(parent[u]);
        dp[u][0] = dp[u][1] = 0;
        for(ll i = head[u]; i != -1; i = e[i].next) {
            dp[u][0]  = max(dp[e[i].to][0], dp[e[i].to][1]);
            dp[u][1]  = dp[e[i].to][0];
        }
        dp[u][1]  = a[u];
    }
    printf("%dn", max(dp[u][0], dp[u][1]));
    return 0;
}
dfs

0 人点赞