【问题标题】:Finding the largest interval using Dynamic programming使用动态规划找到最大间隔
【发布时间】:2014-02-15 14:36:48
【问题描述】:

http://www.cs.uiuc.edu/~jeffe/teaching/algorithms/notes/05-dynprog.pdf 我在练习这些问题时遇到了一个难倒我的问题。

7.(a) 假设给定平面中的一组 L,由 n 个线段组成,其中每个线段在 y = 0 线上有一个端点和一个端点 在 y = 1 线上,所有 2n 个端点都是不同的。描述和 分析一种算法来计算 L 的最大子集,其中没有 一对线段相交。

(b) 假设给定平面上的 n 个线段集合 L, 其中每条线段的端点位于单位圆上 x 2 + y 2 = 1,并且所有 2n 个端点都是不同的。描述和分析一个 计算 L 的最大子集的算法,其中没有一对 段相交。

我想出了如何在 O(n log n) 时间内完成 7a(问题是寻找递增数字的最大子集的变相问题)。我几乎要放弃 7b,因为我想不出办法。

但是,有没有办法将 7b 的前提转换为更像 7a 的前提?我觉得这是解决问题的正确方法,如果能帮助解决这个问题,我们将不胜感激。

【问题讨论】:

  • 已修复,感谢您指出这一点

标签: algorithm dynamic-programming


【解决方案1】:

我想不出一个 O(n*log(n)) 的算法,但这里是一个 O(n2) 的算法。

我们的想法是,我们构建一个有向图,其中顶点表示给定集合中的段,边表示“位于右侧的”关系。

令 L 为段列表:{(a1, b1), (a2, b2 ), ..., (an, bn)},其中 ak 和 bk 是第 k 个段的端点。

令 L' 为段列表:{(a1, b1), (b1, a 1), (a2, b2), (b2, a2) , ..., (an, bn), (bn, an)}。

设图的顶点有1到2*n的索引,每个索引k代表线段L'[k],即(ak/2, bk/ 2) 如果 k 是奇数, (bk/2, ak/2) 如果 k 是偶数。

段(a1, b1) 位于段(a2, b2) 当点 a1, a2, b2, b1 是在单位圆上按顺时针顺序排列。

请注意 1) 如果一个线段位于另一个线段的右侧,它们不会相交; 2) 如果来自 L 的两个线段不相交,则来自 L' 的四个对应线段中的两个必然位于另一个的右侧; 3) L 中任何一组不相交的线段都由 L' 的一系列线段定义,每个线段位于前一个线段的右侧。

算法概述:

for every k1 from 1 to 2*n:
    for every k2 from 1 to 2*n:
        if (L'[k1].a, L'[k1].b) lies to the right of (L'[k2].a, L'[k2].b):
            add a directed edge (k1, k2) to the graph 
Find the longest path in the graph: (k1, k2, ..., km). 
The answer to the problem is: (k1/2, k2/2, ..., km/2).

【讨论】:

  • 您假设所有段都在初始集中可用。这似乎不是问题的假设之一。
  • @DanielTheRocketMan:可用是什么意思?如果你的意思是任何两点是相连的,我不这么认为。
  • 对不起,我想我误解了你的解决方案。我认为你的假设是好的。我只是没明白。可以澄清一下吗?
  • @DanielTheRocketMan:我在第二段中添加了“来自给定集合”。现在清楚了吗?
  • (1) “线段端点的角度”是什么意思——你说的是哪个角度? (2) 点按顺时针顺序排列是什么意思?点还是角? (3) a_i 可以等于 aj,b_i 可以等于 b_j。问题是点不同,而不是角度不同。对不起,如果我真的错过了重点。
【解决方案2】:

这是一个 O(n2) 算法。

我们在圆上有 2n 个端点。选择任何点并开始按顺时针方向从 1 开始按递增顺序标记这些点。因此,我们将点标记为从 12n。因此,任何线段 l 都可以表示为 (i,j),其中 ijl1≤i.

Li,jL 的子集,使得 l=(a,b) ∈ Li,j 如果 i ≤ a 。另外,将 1 ≤ i ≤ j ≤ 2nD[i,j] 定义为 Li 中的最大不相交线数, j。我们需要找到D[1,2n]

我们在这里使用动态规划。如果 ( i,i+1) 为线段,否则设为0。我们可以使用以下代码构建 D:

if (i,j) is a line segment :
     D[i,j] = D[i+1,j-1]+1
else if (i,k) is a line segment and i<k<j :
     D[i,j] = max(D[i,j] , D[i+1,k-1]+D[k+1,j]+1)
else if (k,j) is a line segment and i<k<j :
     D[i,j] = max(D[i,j] , D[i,k-1]+D[k+1,j-1]+1)
else :
     D[i,j] = max(D[i,j] , D[i+1,j-1])

由于 D 占用 O(n2) 空间,并且我们在恒定时间内计算 D 的每个单元格,因此算法的时间复杂度为O(n2).

参考: http://www.cs.toronto.edu/~robere/csc373h/files/A2-sol.pdf

查看标题Line Intersections (Redux)

【讨论】:

  • 尝试添加更多信息,而不仅仅是链接到外部资源。这样其他人可能会发现您的答案很有用,并且在删除 pdf 文件后它仍然有效。
  • 谢谢,等我准备好终稿后会解释算法。
  • 现在好多了。
【解决方案3】:

创建两个列表。第一个列表具有通过从 (1,0) 开始围绕圆逆时针扫描创建的排序。您点击的段的第一个端点被标记。第二个列表的顺序相同,但围绕圆圈顺时针方向排列。以这种方式,您现在有两个列表,其中段端点显示交集的排序。例如,如果第一个列表中的第一个点在第二个列表中没有对应的端点,那么它将与第二个列表中出现在它之前的所有线段相交。 (您需要在这里小心,因为一条线的两个点都可以在您的段的结尾之前。一个简单的检查消除了这一点。)然后您可以运行该列表。这种方法的总复杂度似乎是每个列表创建的 O(n log n) 和运行列表的 O(n)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-29
    • 2012-11-12
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 2010-12-16
    • 2011-12-02
    • 1970-01-01
    相关资源
    最近更新 更多