找到最小的重叠作业集

时间:2012-01-31 09:07:20

标签: algorithm puzzle

一位朋友给了我一个谜题,他说可以比O(n ^ 3)时间更好地解决。

给定一组n个作业,每个作业都有一个设定的开始时间和结束时间(重叠是非常可能的),找到每个作业包含该作业的最小子集,或者包括与该作业重叠的作业。 / p>

我非常确定最佳解决方案是选择具有最多未标记重叠的作业,将其添加到解决方案集,然后标记它及其重叠。并重复,直到所有工作都被标记 确定哪个作业具有最多未标记的重叠是一个简单的邻接矩阵(O(n ^ 2)),每次选择作业时都必须重做,以便更新标记,使其成为O(n ^ 3) )。

有更好的解决方案吗?

2 个答案:

答案 0 :(得分:9)

A成为我们尚未重叠的作业集。

  1. x中找到具有最小结束时间(A)的作业t
  2. 从开始时间小于t的所有工作:选择具有最长结束时间的工作j
  3. j添加到输出集。
  4. j删除所有与A重叠的作业。
  5. 重复1-4,直到A为空。
  6. 一个简单的实现将在O(n ^ 2)中运行。使用interval trees,可能可以在O(n * logn)中解决。

    为什么它是最佳解决方案(不是正式证明)背后的基本思想:我们必须选择一个开始时间小于t的工作,以便x重叠。如果我们让S成为开始时间小于t的所有作业的集合,则可以显示j将与S中的任何作业重叠相同的作业,加上可能更多。由于我们必须在S中选择一项工作,因此最佳选择是j。我们可以利用这个想法通过对工作数量的归纳来形成证据。

答案 1 :(得分:1)

我们可以使用动态编程方法实现O(nlogn)解决方案。特别是,我们要考虑最小集合的大小,包括k th 作业,并匹配第一个k作业(按开始时间排序),我们用{{1}表示}。我们首先应该添加一个辅助作业(∞,∞),因此结果将是我们最终作业的DP解决方案减去一个。

要计算S(k),请考虑作业S(k),该作业在作业p(k)之前结束,但具有最长的开始时间。请注意k是一个增加的函数。 pS(k)S(i)最低end(i) > start(p(k))

我们可以通过维持(S(k)有序最小)潜在工作堆来有效地找到这份工作。在计算每个S(k)之后,我们将作业添加到堆中。当我们想要找到一份工作时,我们会在堆的基础上删除过早结束的工作,直到找到合适的工作。这将最多花费O(nlogn),因为我们最多只执行每个堆操作的O(n)(pop / peek / push)。

剩下的任务是有效地计算p(k)值。一种方法是迭代所有工作的开始和结束(以增加的时间),跟踪最新的起始工作。