我正在尝试解决this problem,其中给出N(N <= 1000)个区间,并且算法应该计算(大小)最大的区间子集,使得子集中没有三个区间共享共同点。现在我只关注动态编程算法。
我的想法是通过完成时间对间隔进行排序,然后考虑以下子问题: A [i] - 仅使用前i个区间来解决问题(即最大间隔数)。
现在我的问题是关于复发:如果采取第i个间隔,那么我无法弄清楚复发。
有人可以解释我做错的地方(是子问题定义还是我只是错过了重复子问题)?
编辑(新主意?)
经过一些研究,我发现这个DP solution用于一般的Job Selection算法。因此,下一个想法是拥有q
数组,其中q[i]
=与第i个时间间隔没有重叠的最后一个时间间隔的索引。
然后可以肯定的是,当第i个间隔被采用时计算A [i]的公式将是类似的(注意缺失的部分):
A[i] = 1 + A[q[i]] + [missing-part];
//1 stands for the i-th interval
//A[q[i]] stands for the solution of the intervals that do not overlap with with the i-th interval
//[missing-part] is the maximum number of intervals from the intervals that overlap with the i-th intervals that are safe to be added.
问题仍然存在:如何计算丢失的部分?
编辑(贪婪的解决方案,而不是想要的解决方案) 贪婪的解决方案非常简单,与Job Selection Problem非常相似,并且额外检查在添加新间隔时,必须保留没有未处理的间隔来打破问题的条件。
答案 0 :(得分:0)
虽然我无法想到动态编程解决方案,但我至少可以想到一个有效的解决方案,无论如何都可能有所帮助:
查找间隔的所有成对重叠。如果我们将区间想象为数字线上的线段,那么我们可以使用线扫描算法在O(n log n)中有效地执行此操作,该算法通过起始位置减少到排序间隔,然后对它们进行线性扫描。 / p>
将问题转换为图表。每个输入间隔是图中的一个节点。在具有重叠的节点之间添加无向边。或者,您可以将无向边视为2个相反方向的有向边。例如,如果间隔A和B重叠,则绘制A和B之间的无向边,或者绘制从A到B的有向边,并绘制从B到A的有向边。后一种表示可能最适合下一步。
使用Tarjan算法查找图中的所有周期。这具有复杂度O(E + V)或大致O(N)。该算法找到强连通分量,这与循环相同。只保留长度> = 3的循环,因为这意味着3个间隔共享一个公共点,这违反了我们的约束。从现在开始,假设有K个周期。
对于剩余的周期,建立一个频率列表,列出一个周期中任何节点出现的频率。使用散列映射,在所有循环的总长度中具有O(n)复杂度。
观察从循环中删除任何1个节点会中断该循环。如果我们删除M个循环中发生的节点,我们将破坏M个循环。我们的目标是打破所有K个循环,并通过删除尽可能少的节点来实现。为此,迭代删除最常出现的节点,直到不再存在循环。我们最终会得到一组删除的间隔。该集合的补充是一组间隔,使得没有3共享一个共同点。这个补充集的基数是我们的解决方案。
我相信我们可以在O(n log n)时间内执行第5步,如果我们在完成散列后按频率对元素进行排序,然后重复删除最频繁的元素,打破与元素关联的所有循环,导致我们也删除这些循环中的所有节点。实际上,我们实际上可以在线性时间内完成它,因为我们的频率将是线性计数,因此我们可以使用桶或基数排序。从断开周期中删除节点也是线性时间,因为我们最多会删除它们中的所有N个,然后再也不会考虑它们。
上面的文字很糟糕,因为找到要移除的最小顶点集以打破所有周期是NP-Complete,并且被称为计算反馈顶点集(http://en.wikipedia.org/wiki/Feedback_vertex_set)。这个问题的已知确切解决方案是指数级的。