跳转至

贪心算法

活动选择问题

给定一个活动集合 \(S = \{a_1, a_2, \ldots, a_n\}\),其中每个活动都有一个开始时间 \(s_i\) 和结束时间 \(f_i\),且 \(0 \leqslant s_i < f_i < \infty\)。如果活动 \(a_i\) \(a_j\) 满足 \(f_i \leqslant s_j\) \(f_j \leqslant s_i\),则称活动 \(a_i\) \(a_j\) 是兼容的。活动选择问题就是要找到一个最大的兼容活动子集。

假设输入是按照 \(n\) 个活动的结束时间由小到大排序的。我们当然可以先使用动态规划来解决这个问题:

Dynamic Programming

  • \(S_{ij}\) 是活动 \(a_i\) \(a_j\) 之间的最大兼容活动子集,其大小记为 \(c_{ij}\),那么我们有如下的递推关系:
\[ c_{ij} = \max \{c_{ik} + c_{kj} + 1 \mid f_i \leqslant s_k < f_k \leqslant s_j\}. \]
  • \(S_i\) 是活动 \(a_1, a_2, \ldots, a_i\) 的最大兼容活动子集,其大小记为 \(c_i\),那么我们有如下的递推关系:
\[ c_i = \max \{c_{i - 1}, c_{k(i)} + 1\}, \]

其中 \(k(i)\) 表示在 \(1 \leqslant k \leqslant i\) 中,\(f_k \leqslant s_i\) \(c_k\) 最大的 \(k\),即不与 \(a_i\) 冲突的最晚结束的活动。

但以上的动态规划算法的时间复杂度为 \(O(n^2)\),但我们希望使用更加高效的算法来解决这个问题,于是我们引入了贪心算法。

但是贪心算法的策略设计也并不是那么容易,比如从前到后选择开始最早且不冲突的活动就不是正确的策略。可能正确的一个贪心策略便是从前到后选择结束最早的活动,下面我们证明其正确性。

\(S_k = \{a_i \in S \mid f_k \geqslant s_i\}\),即 \(S_k\) 为在 \(a_k\) 结束之后开始的活动集合。当我们做出贪心选择,选择了 \(a_1\) 后,剩下我们只需要求解 \(S_1\) 这一子问题即可。如果 \(a_1\) 确实在最优解中,那么原问题的最优解显然就由活动 \(a_1\) 及子问题 \(S_1\) 的最优解构成。然后 \(S_1\) 内我们又可以按照贪心策略选择新的结束时间最早的活动,以此类推得到全部的解。所以问题归结到了 \(a_1\) 是否在最优解中。

活动选择问题贪心选择性质

考虑任意非空子问题 \(S_k\),令 \(a_m\) \(S_k\) 中结束时间最早的活动,则 \(a_m\) \(S_k\) 的某个最大兼容活动子集中 .

Proof

\(A_k\) \(S_k\) 的一个最大兼容活动子集且 \(a_j\) \(A_k\) 中结束时间最早的活动。若 \(a_j\) = \(a_m\),则已经证明 \(a_m\) \(S_k\) 的某个最大兼容活动子集中;若 \(a_j \neq a_m\),令集合 \(A'_k = (A_k - \{a_j\}) \cup \{a_m\}\),即将 \(A_k\) 中的 \(a_j\) 替换为 \(a_m\),显然 \(A'_k\) 也是 \(S_k\) 的一个最大兼容活动子集,且 \(a_m\) 在其中。

有了这样选择性质,我们便可以说明贪心算法的最优子结构:

活动选择问题最优子结构

在活动选择问题中,用贪心策略选择 \(a_1\) 之后得到子问题 \(S_1\),那么 \(a_1\) 和子问题 \(S_1\) 的最优解合并一定可以得到原问题的一个最优解 .

Proof

使用反证法。假设 \(a_1\) 和子问题 \(S_1\) 的最优解 \(C_1\) 合并得到的解 \(C\) 不是原问题的一个最优解,那么假设 \(C'\) 为原问题的一个最优解,则 \(\lvert C \rvert < \lvert C' \rvert\)。依据贪心选择性质,如果用 \(a_1\) 替代 \(C\) 中的第一个活动,得到的解 \(C''\) 不会比 \(C'\) 更差,即 \(\lvert C'' \rvert \geqslant \lvert C' \rvert\),那么将 \(C''\) 除去 \(a_1\) 后,剩余的部分其实也是子问题 \(S_1\) 的一个解 \(C''_1\)。因为 \(\lvert C'' \rvert \geqslant \lvert C \rvert\),所以 \(\lvert C''_1 \rvert \geqslant \lvert C_1 \rvert\),这与 \(C_1\) 是子问题 \(S_1\) 的最优解矛盾。