P2014 [CTSC1997] 选课

P2014 [CTSC1997] 选课

大意

有些学科 \(i\) 有先修课 \(fa\) 这些课程形成了一个树形结构,问选 \(m\) 门课所能达到的最大的学分。

思路

考虑树上背包。

我们定义 \(f_{u,j}\) 表示在 \(u\) 子树内选 \(j\) 门课的最大学分,类似我们的背包,我们采用倒序枚举,保证转移的正确性。

枚举 \(j\),表示 \(u\) 这颗子树选 \(j,j \in [m, 0]]\) 个,再枚举 \(k\) 表示在子树 \(v\) 中选 \(k(k \in [0, j))\) 个,显然有转移方程:

\[f_{u, j} = \max(f_{u,j}, f_{u,j - k} + f_{v, k}) \]

然后就是重要的上下界优化了,刚刚的代码时间复杂度在大概 \(\mathcal{O}(nm^2)\) 的,但是很多情况没必要去考虑。

首先就是我们的 \(j\),你要想选几个得看 \(sz_u\),于是我们就可以将 \(j\) 的上界定为 \(\min(sz_u, m)\),下界就是 \(0\),不需要改动。

接着就是 \(k\) 的枚举,若你在子树 \(u\) 内选了 \(j\) 个,那么如果在子树 \(v\) 之外的点有 \(sz_u - sz_v\) 个,而为了选 \(j\) 个,我们在 \(v\) 内只是至少要选 \(j - (sz_u - sz_v)\) 个才可能保证能选出 \(j\) 个,上界和刚刚同理,为 \(\min(j - 1, sz_v)\)

经过这样的优化,可以得出复杂度为 \(\mathcal{O}(nm)\)

证明如下:

1. 符号定义

符号 数学定义
\(n\) 树的节点总数
\(\text{child}(u)\) 节点\(u\)的所有子节点构成的集合
\(\text{siz}(u)\) \(u\)为根的子树包含的节点数量(子树大小)
\(T(u)\) 处理以\(u\)为根的子树所需的总时间
\(t(u)\) 合并\(u\)的所有子树、处理节点\(u\)本身的时间(不含子树递归处理时间)
\(m\) 背包容量(问题中最多选择的节点数,枚举范围受\(m\)约束)

2. 无背包容量约束时的\(O(n^2)\)复杂度证明

2.1 总时间的递归表达式

处理子树\(u\)的总时间等于其所有子节点子树的处理时间之和,加上合并子树的时间:

\[T(u) = \sum_{v \in \text{child}(u)} T(v) + t(u) \]

2.2 合并时间\(t(u)\)的化简

\(\text{child}(u) = \{v_1, v_2, \dots, v_k\}\),合并子树时的时间\(t(u)\)满足:

\[t(u) = 1 + \sum_{i=1}^{|\text{child}(u)|} \left(1 + \sum_{j=1}^i \text{siz}(v_j)\right) \cdot \text{siz}(v_i) \]

由子树大小的定义 \(\text{siz}(u) = 1 + \sum_{v \in \text{child}(u)} \text{siz}(v)\),可化简得:

\[t(u) = O\left(\text{siz}(u)^2\right) \]

2.3 归纳法证明\(T(u) = O(\text{siz}(u)^2)\)
  • 基例(叶子节点)
    \(u\) 为叶子节点,则 \(\text{child}(u) = \emptyset\),此时:

    \[T(u) = t(u) = 1 = O(1^2) = O(\text{siz}(u)^2) \]

  • 归纳步
    假设对 \(\forall v \in \text{child}(u)\),均有 \(T(v) = O(\text{siz}(v)^2)\),则:

    \[\sum_{v \in \text{child}(u)} T(v) = O\left(\sum_{v \in \text{child}(u)} \text{siz}(v)^2\right) \]

    由平方和不等式 \(\sum_{v \in \text{child}(u)} \text{siz}(v)^2 \leq \left(\sum_{v \in \text{child}(u)} \text{siz}(v)\right)^2 = (\text{siz}(u)-1)^2\),得:

    \[\sum_{v \in \text{child}(u)} T(v) = O\left(\text{siz}(u)^2\right) \]

    结合 \(t(u) = O(\text{siz}(u)^2)\),最终有:

    \[T(u) = O\left(\text{siz}(u)^2\right) \]

2.4 全局复杂度

遍历所有节点求和,树的所有子树大小的平方和满足 \(\sum_{u} \text{siz}(u)^2 = O(n^2)\),因此:

\[\sum_{u} T(u) = O\left(\sum_{u} \text{siz}(u)^2\right) = O(n^2) \]

3. 加入背包容量\(m\)后的\(O(nm)\)复杂度证明

3.1 合并时间\(t(u)\)的修正(加入\(m\)约束)

背包容量限制枚举范围,\(t(u)\) 修正为:

\[t(u) = 1 + \sum_{i=1}^{|\text{child}(u)|} \min\left(m, 1 + \sum_{j=1}^i \text{siz}(v_j)\right) \cdot \min\left(m, \text{siz}(v_i)\right) \]

化简得:

\[t(u) = O\left(\min(\text{siz}(u), m) \cdot \text{siz}(u)\right) \]

3.2 分情况推导\(T(u)\)
  • 情况1:\(\text{siz}(u) \leq m\)
    此时 \(\min(\text{siz}(u), m) = \text{siz}(u)\),故:

    \[T(u) = O\left(\text{siz}(u)^2\right) \]

  • 情况2:\(\text{siz}(u) > m\)
    \(\text{child}(u)\)分为两类:

    \[S_1 = \{v \in \text{child}(u) \mid \text{siz}(v) \leq m\}, \quad S_2 = \{v \in \text{child}(u) \mid \text{siz}(v) > m\} \]

    对两类子节点分别求和:

    \[\sum_{v \in S_1} T(v) = O\left(\left(\sum_{v \in S_1} \text{siz}(v)\right)^2\right) = O(m^2) \]

    \[\sum_{v \in S_2} T(v) = O\left(m \cdot \sum_{v \in S_2} \text{siz}(v)\right) \]

    结合 \(t(u) = O(m \cdot \text{siz}(u))\),最终得:

    \[T(u) = O\left(m \cdot \text{siz}(u)\right) \]

3.3 全局复杂度

遍历所有节点求和,结合 \(\min(\text{siz}(u), m) \cdot \text{siz}(u)\) 的上界约束:

\[\sum_{u} T(u) = O\left(\sum_{u} \min(\text{siz}(u), m) \cdot \text{siz}(u)\right) = O(nm) \]

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 310;
vector<int> g[N];
int f[N][N], n, m, siz[N];
void dfs(int u) {
    siz[u] = 1;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        dfs(v);
        siz[u] += siz[v];
        for (int j = min(m, siz[u]); j >= 0; --j) {
            for (int k = max(1, j - siz[u] + siz[v]); k <= min(j - 1, siz[v]); ++k) {
                f[u][j] = max(f[u][j], f[u][j - k] + f[v][k]);
            }
        }
    }
}
int main() {
    cin >> n >> m;
    m++;
    for (int i = 1; i <= n; ++i) {
        int fa, val;
        cin >> fa >> val;
        g[fa].push_back(i);
        f[i][1] = val;
    }
    dfs(0);
    cout << f[0][m];
    return 0;
}
posted @ 2025-12-12 22:34  To_Carpe_Diem  阅读(3)  评论(0)    收藏  举报