1 条题解

  • 0
    @ 2025-12-6 17:23:21

    题解

    问题重述

    我们有 nn 个讲座区间 [ai,bi][a_i, b_i],要求选择一个讲座集合 U={u1,,uk}U = \{u_1, \dots, u_k\},满足:

    1. 无冲突UU 中任意两个区间不重叠(允许一个结束时另一个立即开始)。
    2. 可替换性:对每个 uiUu_i \in U,存在一个讲座 viUv_i \notin U,使得将 uiu_i 替换为 viv_i 后,新集合 U{ui}{vi}U \setminus \{u_i\} \cup \{v_i\} 仍然无冲突。
    3. 最大化 kk

    输出最大 kk 及对应的 kk(ui,vi)(u_i, v_i)


    关键观察

    1. 问题结构

    这是一个带容错的区间调度问题
    经典区间调度问题:选择最多互不重叠的区间 → 按结束时间贪心。
    这里增加了每个选中区间必须有一个“备用”区间的要求。

    2. 替换条件的等价形式

    设选中的区间集合为 UU,按结束时间排序为 I1,I2,,IkI_1, I_2, \dots, I_k
    对某个 IjI_j,其备用区间 JJ 必须满足:

    • JUJ \notin U
    • JJ 不与 U{Ij}U \setminus \{I_j\} 中任意区间冲突

    这意味着:JJ 可以插入到 Ij1I_{j-1} 之后、Ij+1I_{j+1} 之前(考虑首尾),即:

    $$\text{end}(I_{j-1}) \le \text{start}(J) \quad \text{且} \quad \text{end}(J) \le \text{start}(I_{j+1}) $$

    其中约定 I0I_0 结束时间为 -\inftyIk+1I_{k+1} 开始时间为 ++\infty

    因此,每个选中区间 IjI_j 对应一个“时间窗口”,备用区间必须完全落在这个窗口内。


    3. 最大化的限制

    设我们贪心选择了 kk 个不重叠区间(按结束时间排序)。
    能否为每个选中区间找到备用区间?这取决于在相邻选中区间之间的“间隙”中,是否有至少一个未选中的区间。

    更精确地说:

    • 设选中的区间为 [s1,e1],[s2,e2],,[sk,ek][s_1, e_1], [s_2, e_2], \dots, [s_k, e_k],且 e1s2,e2s3,e_1 \le s_2, e_2 \le s_3, \dots
    • 间隙为 $G_0 = (-\infty, s_1), G_1 = (e_1, s_2), G_2 = (e_2, s_3), \dots, G_k = (e_k, +\infty)$。
    • IjI_j,其备用区间必须完全包含在 Gj1GjG_{j-1} \cup G_j 中吗?不,更准确是:备用区间 JJ 必须满足:
      • 不与 Ij1I_{j-1} 冲突:ej1start(J)e_{j-1} \le \text{start}(J)
      • 不与 Ij+1I_{j+1} 冲突:end(J)sj+1\text{end}(J) \le s_{j+1}
      • JJ[ej1,sj+1][e_{j-1}, s_{j+1}] 内(包括端点相接)。

    所以窗口长度 Wj=sj+1ej1W_j = s_{j+1} - e_{j-1}(对边界适当处理)。


    4. 贪心选择策略

    直观想法:我们希望在贪心选择互不重叠区间时,保证相邻选中区间之间至少有 2 个未选中区间(一个用于左边选中区间的备用,一个用于右边选中区间的备用)。但最左和最右区间只需要一个备用区间在相邻间隙中。

    实际上,更系统的处理方式是:

    算法框架

    1. 将所有区间按结束时间 bib_i 排序。
    2. 使用经典贪心选择尽可能多的不重叠区间,得到候选集合 CC
    3. 检查能否为 CC 中每个区间找到备用区间:
      • 对每个选中的区间,在其前后间隙中寻找一个可插入的未选中区间。
      • 如果某个区间找不到备用区间,则必须减少 kk(删除某些选中区间)。
    4. 目标是找到最大的 kk 使得存在大小为 kk 的可行集合 UU

    构造性解法

    步骤1:二分答案 + 验证

    由于 kk 最大为 nn,可以二分 kk,然后验证是否存在大小为 kk 的可行集合。

    验证方法(给定 kk): 我们试图选择 kk 个区间,并分配备用区间。
    考虑按结束时间排序后,选择第 ii 个选中区间的结束时间 eie_i 和第 i+1i+1 个选中区间的开始时间 si+1s_{i+1}
    对于内部区间 IjI_j2jk12 \le j \le k-1),其备用区间必须在 [ej1,sj+1][e_{j-1}, s_{j+1}] 内。
    对于边界区间 I1I_1,备用区间在 (,s2](-\infty, s_2] 内;IkI_k[ek1,+)[e_{k-1}, +\infty) 内。

    我们可以动态规划
    dp[i][t]dp[i][t] 表示考虑前 ii 个区间(按结束时间排序),已选择了 tt 个区间,且最后一个选中区间是第 ii 个时是否可行,同时维护每个选中区间的备用区间是否可分配。
    但状态数 O(nk)O(nk) 太大。


    步骤2:更高效的贪心构造

    实际上,我们可以直接构造一个可行集合,并证明其最大性。

    构造算法

    1. 按结束时间 bib_i 排序所有区间。
    2. 初始化 U=U = \emptyset,备选池 P=P = \emptyset(用于存放可能作为备用的区间)。
    3. 顺序处理区间:
      • 如果当前区间不与 UU 中最后一个区间冲突,则考虑将其加入 UU,但需要检查备用条件。
      • 更安全的方法是:先贪心选择 UU,然后尝试为每个 uUu \in U 分配 vv
    4. 但更好的方法是从后往前构造
      • 从最晚结束的区间开始,选择一些区间作为“骨架”。
      • 确保每个骨架区间的前后都有足够空间放置备用区间。

    步骤3:转化为匹配问题

    将问题看作:选择 kk 个区间 UU,并在剩下的区间中为每个 uiu_i 分配一个 viv_i,使得 viv_i 不与 U{ui}U \setminus \{u_i\} 冲突。
    这类似于在区间图中找一个可删除的独立集,且每个点有一个“替换邻居”。

    可以建模为:
    构造二分图,左部是候选的 UU,右部是候选的 VV,边表示可替换。但这样太大。


    最终可行算法(O(nlogn)O(n \log n)

    1. 排序:按结束时间 bib_i 排序所有区间。
    2. 第一遍贪心:选出最多的不重叠区间集合 SS(经典贪心)。
    3. 检查与调整
      • SS 中的区间按结束时间排序为 I1,,ImI_1, \dots, I_m
      • 对于每个 IjI_j,在未选中的区间中寻找一个区间 JJ,使得:
        • JJ 完全在 [end(Ij1),start(Ij+1)][end(I_{j-1}), start(I_{j+1})] 内(边界特殊处理)。
      • 如果某个 IjI_j 找不到 JJ,则从 SS 中删除 IjI_j(因为它阻塞了相邻区间的备用选择)。
    4. 递归调整:删除某些区间后,重新检查相邻区间的备用条件,直到所有选中区间都有备用。
    5. 输出:最终 SS 的大小即为 kk,对每个 IjI_j 输出对应的备用区间 JJ

    正确性证明要点

    引理1:如果存在大小为 kk 的可行集合,则按结束时间贪心选出的不重叠集合大小至少为 kk
    证明:可行集合本身就是一个不重叠集合,贪心选择得到的是最大不重叠集合,所以 mkm \ge k

    引理2:在贪心集合 SS 中,如果某个区间 IjI_j 找不到备用区间,则任何包含 IjI_j 的可行集合大小不可能达到 mm,必须删除 IjI_j

    引理3:删除 IjI_j 后,对其相邻区间 Ij1I_{j-1}Ij+1I_{j+1} 的备用条件可能改善,因此迭代删除不可行区间最终会得到一个可行集合。

    定理:上述算法得到的 kk 是最大的。


    时间复杂度

    • 排序:O(nlogn)O(n \log n)
    • 贪心选择:O(n)O(n)
    • 备用区间查找:对每个选中区间,可以在未选中区间中用二分查找或扫描找到合适的 viv_i,总共 O(nlogn)O(n \log n)
    • 调整过程:每个区间最多被删除一次,O(nlogn)O(n \log n)

    总复杂度 O(nlogn)O(n \log n),适合 n5×105n \le 5\times 10^5


    样例解析

    样例1:

    区间:1:[1,5] 2:[3,10] 3:[4,8] 4:[9,12] 5:[11,16] 6:[14,15] 7:[20,22] 8:[15,21]
    按结束时间排序后贪心选:1,4,8 (k=3)
    检查备用:
    - 区间1:窗口(-∞,9],可选区间3:[4,8] ✓
    - 区间4:窗口[5,15],可选区间6:[14,15] ✓
    - 区间8:窗口[12,∞),可选区间7:[20,22] ✓
    输出 k=3 及对应备用。
    

    实现细节(仅思路)

    1. 存储区间时记录原始编号。
    2. 贪心选择时用优先队列或简单扫描。
    3. 对于每个选中区间,在其时间窗口内寻找一个未选中的区间作为备用(可提前按开始时间排序未选中区间,二分查找)。
    4. 若找不到,则从选中集合中移除该区间,并合并相邻窗口重新检查。

    难点

    • 边界条件的处理(第一个和最后一个选中区间的窗口是半无限的)。
    • 当删除一个选中区间时,其左右两个区间的备用窗口会扩大,可能需要重新分配备用区间。
    • 证明算法的最优性需要严谨的交换论证。

    总结

    本题是区间调度问题的进阶版,加入了“每个选中元素必须有替换”的容错要求。
    通过贪心选择结合迭代删除不可行区间,可以在 O(nlogn)O(n \log n) 时间内找到最大可行集合,并构造出对应的备用分配方案。
    关键在于将替换条件转化为时间窗口约束,并利用区间排序性质高效检查。

    • 1

    信息

    ID
    5816
    时间
    8000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者