带权重的区间调度问题(最大化总权重,区间不重叠)
字数 2061 2025-12-08 18:00:46

带权重的区间调度问题(最大化总权重,区间不重叠)

题目描述
给定一系列工作,每个工作有开始时间 start[i]``、结束时间 end[i]和权重profit[i]`,表示完成这个工作能获得的收益。你希望选择一组不重叠的工作(即任意两个被选工作的时间段不重叠),使得这些工作的总权重(总收益)最大。请返回最大总收益。

示例:
输入:start = [1,2,3,3], end = [3,4,5,6], profit = [50,10,40,70]
输出:120
解释:选择工作0(收益50)和工作3(收益70),总收益120,它们的时间段 [1,3) 和 [3,6) 不重叠。


解题思路讲解

这个问题是经典“区间调度”的带权版本。如果我们只要求数量最多,可以用贪心(按结束时间排序,选最早结束且不冲突的),但这里每个工作权重不同,贪心可能不是最优,所以需要用动态规划。


第一步:问题分析与预处理

  1. 状态定义
    我们需要考虑按某种顺序处理工作。一个自然的想法是:将工作按结束时间排序,这样当我们决定是否做某个工作时,只需要关心在它之前结束的工作。
    定义 dp[i] 表示考虑前 i 个工作(按结束时间排序后),并且一定选择第 i 个工作时,能获得的最大收益。
    但这样定义不方便直接递推,因为“选择第 i 个工作”意味着我们不能选任何与它时间重叠的工作。

    更常用的定义是:dp[i] 表示考虑前 i 个工作(排序后),能获得的最大收益(不一定要选第 i 个)。
    这样,对于第 i 个工作,有两种选择:

    • 不选它:dp[i] = dp[i-1]
    • 选它:收益是 profit[i] + dp[p(i)],其中 p(i) 是在第 i 个工作开始之前结束的最后一个工作的下标(即不冲突的前一个工作)。

    所以:dp[i] = max(dp[i-1], profit[i] + dp[p(i)])

  2. 排序与 p(i) 的计算
    我们先创建一个工作列表,每个工作包括 (start, end, profit),然后按 end 升序排序。
    对于每个 i,我们需要找到最大的 j 满足 end[j] <= start[i]。因为数组已按 end 排序,所以可以用二分查找快速得到 p(i)。


第二步:详细递推过程

假设有 n 个工作,排序后编号 0 到 n-1。
我们定义 dp[0] = profit[0](只有一个工作时,最大收益就是选它)。
对于 i >= 1:

  • 找到 p(i) 使得 end[p(i)] <= start[i] 且 p(i) 尽可能大。如果找不到,记 p(i) = -1。
  • 选择 i 的收益 = profit[i] + (p(i) >= 0 ? dp[p(i)] : 0)
  • 不选 i 的收益 = dp[i-1]
  • dp[i] = max(选 i 的收益, 不选 i 的收益)

最终答案 = dp[n-1]


第三步:示例推演

输入:start = [1,2,3,3], end = [3,4,5,6], profit = [50,10,40,70]
排序(按 end):
工作0: (1,3,50)
工作1: (2,4,10)
工作2: (3,5,40)
工作3: (3,6,70)

计算 p(i):

  • i=0: start[0]=1,找 end <= 1 的工作,没有 → p(0) = -1
  • i=1: start[1]=2,找 end <= 2 的工作,没有 → p(1) = -1
  • i=2: start[2]=3,找 end <= 3 的工作,工作0的 end=3 满足 → p(2) = 0
  • i=3: start[3]=3,找 end <= 3 的工作,工作0满足 → p(3) = 0

dp 计算:

  • dp[0] = profit[0] = 50
  • i=1: 选 = 10 + 0 = 10,不选 = 50 → dp[1] = 50
  • i=2: 选 = 40 + dp[0] = 40+50=90,不选 = dp[1]=50 → dp[2] = 90
  • i=3: 选 = 70 + dp[0] = 70+50=120,不选 = dp[2]=90 → dp[3] = 120

答案 = 120。


第四步:算法复杂度

排序 O(n log n),计算每个 p(i) 二分查找 O(log n),总 O(n log n)。空间 O(n) 存 dp。


第五步:关键点总结

  1. 按结束时间排序,保证“前面”的工作不会与当前工作冲突(如果结束时间 ≤ 开始时间)。
  2. 状态定义为“考虑前 i 个工作的最大收益”,决策是选或不选当前工作。
  3. 选当前工作时,收益要加上它之前最后一个不冲突工作的 dp 值,这体现了“不重叠”约束。

这样,我们通过排序 + 二分 + 动态规划,解决了带权区间调度的最大化收益问题。

带权重的区间调度问题(最大化总权重,区间不重叠) 题目描述 给定一系列工作,每个工作有开始时间 start[i]``、结束时间 end[ i] 和权重 profit[ i] ` ,表示完成这个工作能获得的收益。你希望选择一组不重叠的工作(即任意两个被选工作的时间段不重叠),使得这些工作的总权重(总收益)最大。请返回最大总收益。 示例: 输入:start = [ 1,2,3,3], end = [ 3,4,5,6], profit = [ 50,10,40,70 ] 输出:120 解释:选择工作0(收益50)和工作3(收益70),总收益120,它们的时间段 [ 1,3) 和 [ 3,6) 不重叠。 解题思路讲解 这个问题是经典“区间调度”的带权版本。如果我们只要求数量最多,可以用贪心(按结束时间排序,选最早结束且不冲突的),但这里每个工作权重不同,贪心可能不是最优,所以需要用动态规划。 第一步:问题分析与预处理 状态定义 我们需要考虑按某种顺序处理工作。一个自然的想法是:将工作按结束时间排序,这样当我们决定是否做某个工作时,只需要关心在它之前结束的工作。 定义 dp[i] 表示考虑前 i 个工作(按结束时间排序后),并且 一定选择第 i 个工作 时,能获得的最大收益。 但这样定义不方便直接递推,因为“选择第 i 个工作”意味着我们不能选任何与它时间重叠的工作。 更常用的定义是: dp[i] 表示考虑前 i 个工作(排序后),能获得的最大收益(不一定要选第 i 个)。 这样,对于第 i 个工作,有两种选择: 不选它: dp[i] = dp[i-1] 选它:收益是 profit[i] + dp[p(i)] ,其中 p(i) 是在第 i 个工作开始之前结束的最后一个工作的下标(即不冲突的前一个工作)。 所以: dp[i] = max(dp[i-1], profit[i] + dp[p(i)]) 排序与 p(i) 的计算 我们先创建一个工作列表,每个工作包括 (start, end, profit),然后按 end 升序排序。 对于每个 i,我们需要找到最大的 j 满足 end[j] <= start[i] 。因为数组已按 end 排序,所以可以用二分查找快速得到 p(i)。 第二步:详细递推过程 假设有 n 个工作,排序后编号 0 到 n-1。 我们定义 dp[0] = profit[0] (只有一个工作时,最大收益就是选它)。 对于 i >= 1: 找到 p(i) 使得 end[p(i)] <= start[i] 且 p(i) 尽可能大。如果找不到,记 p(i) = -1。 选择 i 的收益 = profit[i] + (p(i) >= 0 ? dp[p(i)] : 0) 不选 i 的收益 = dp[i-1] dp[i] = max(选 i 的收益, 不选 i 的收益) 最终答案 = dp[n-1] 。 第三步:示例推演 输入:start = [ 1,2,3,3], end = [ 3,4,5,6], profit = [ 50,10,40,70 ] 排序(按 end): 工作0: (1,3,50) 工作1: (2,4,10) 工作2: (3,5,40) 工作3: (3,6,70) 计算 p(i): i=0: start[ 0]=1,找 end <= 1 的工作,没有 → p(0) = -1 i=1: start[ 1]=2,找 end <= 2 的工作,没有 → p(1) = -1 i=2: start[ 2]=3,找 end <= 3 的工作,工作0的 end=3 满足 → p(2) = 0 i=3: start[ 3]=3,找 end <= 3 的工作,工作0满足 → p(3) = 0 dp 计算: dp[ 0] = profit[ 0 ] = 50 i=1: 选 = 10 + 0 = 10,不选 = 50 → dp[ 1 ] = 50 i=2: 选 = 40 + dp[ 0] = 40+50=90,不选 = dp[ 1]=50 → dp[ 2 ] = 90 i=3: 选 = 70 + dp[ 0] = 70+50=120,不选 = dp[ 2]=90 → dp[ 3 ] = 120 答案 = 120。 第四步:算法复杂度 排序 O(n log n),计算每个 p(i) 二分查找 O(log n),总 O(n log n)。空间 O(n) 存 dp。 第五步:关键点总结 按结束时间排序,保证“前面”的工作不会与当前工作冲突(如果结束时间 ≤ 开始时间)。 状态定义为“考虑前 i 个工作的最大收益”,决策是选或不选当前工作。 选当前工作时,收益要加上它之前最后一个不冲突工作的 dp 值,这体现了“不重叠”约束。 这样,我们通过排序 + 二分 + 动态规划,解决了带权区间调度的最大化收益问题。