如何找到给定 N 切割的无限杆的最大段数

Posted

技术标签:

【中文标题】如何找到给定 N 切割的无限杆的最大段数【英文标题】:How to find maximum number of segments of a infinite rod with given N cuts 【发布时间】:2014-01-22 15:51:03 【问题描述】:

假设我们有一根无限长的杆,并且我们也有 N 段,如 [L1 , L2)。 这意味着我们可以在 L1 和 L2 之前切割杆以获得一段。一些段可能重叠。

例如给定 N=4 和

[2,3)
[1,9)
[4,5)
[5,8)

We can chose

[2,3)
[4,5)
[5,8)

segments 以获得最多三个段。我不知道是否有任何众所周知的好算法?如果有请建议我。我可以手动完成,但无法获得一个好的工作算法。

【问题讨论】:

为了清楚起见,您得到了一个可能的片段列表,其中一些可能与其他片段重叠,并且您想要生成最大数量的非重叠片段的列表子集? 【参考方案1】:

这似乎与找到一组最大的不重叠片段的任务相同。 关于 Codility。

我想解释一下解决这个任务的贪心算法以及在 C++ 中的实现。

    如果输入为空,则返回零,因为没有可用的段。

    如果输入不为空,则至少有一个不重叠的段,即第一个段。将 B 输入中 this 的结束设置为当前结束。

    当前端用于比较A值。下一个可接受的 A-B 的 A 值需要大于当前端才能将其添加到非重叠段中。

    如果是,则递增计数器,并将当前 A-B 对的结尾设置为当前结尾,以供后续比较。

    迭代直到我们到达对的末尾。

这个解决方案的运行时复杂度是O(N),因为我们通过 循环中的对。

这个解决方案的空间复杂度是O(1),因为我们只分配 用于解决任务的恒定内存,与输入数量无关。

int solution(vector<int> &A, vector<int> &B)                                    
                                                                               
  if (A.empty()) return 0;                                                      
  const int N = A.size();                                                       
  int max_nonoverlapping_segments = 1;                                          
  for (int i = 1, end = B.front(); i < N; ++i)                                 
    if (A[i] > end)  ++max_nonoverlapping_segments; end = B[i];               
                                                                               
  return max_nonoverlapping_segments;                                           

【讨论】:

【参考方案2】:

按端点排序。

遍历段,选择不会与之前的段重叠的段(这可以通过简单地跟踪最后一个终点并检查起点是否在该点之后来检查)。

这将始终给出最佳解决方案。

对于您的示例,排序后,我们有:

[2,3)
[4,5)
[5,8)
[1,9)

然后我们遍历[2,3)[4,5)[5,8)[1,9),选择除[1,9) 之外的所有这些。

为什么这是最佳选择

显然,具有最小端点的线段将成为我们的选择之一,因为任何与其重叠的线段都会有更大的端点,因此可能会与更多以更大值开始的线段重叠,并且任何线段 B 重叠具有最小端点的线段A也将与与A重叠的任何线段重叠,因此B不能是比A更好的选择。

从这里开始,我们对具有最小端点且不与前一个端点重叠的下一段重复此参数,直到我们到达终点。

【讨论】:

我正要写同样的答案。这是一个或多或少众所周知的贪心问题(我知道它是“安排最大数量的节目而不重叠”)。【参考方案3】:

这实际上是动态编程与贪心编程最常见的例子之一。 我实际上只能给你这个链接:http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ 它将向您展示执行此操作的动态方式。 杜克林答案是一种贪心算法。

动态和贪婪有什么区别? 让我用钱告诉你。 假设您有 123 美元,并且有 1 美元、2 美元、5 美元、10 美元、20 美元、50 美元的钞票。如何用最少的账单做到这一点?

Greedy 总是选择当下的最佳选择。它将在特定时刻获得最大的账单。所以首先需要 50,然后是 50,然后是 20,然后是 2,然后是 1。

但是如果我们有 100 美元、1 美元、99 美元、24 美元这样的账单呢? 贪婪会先拿 100,然后再拿 1 美元 23 次。

dynamic 所做的是根据之前做出的决策分析当前决策并纠正过去不正确的决策。这样,您将始终获得最少数量的硬币。 (http://www.geeksforgeeks.org/dynamic-programming-set-7-coin-change/)

所以: 动态:

慢 始终准确 更难

贪婪:

直截了当 并不总是准确的(猜猜为什么只有 1 美元、2 美元、5 美元,而这些乘以 10 :D) 快

【讨论】:

我的解决方案是贪婪的,但它也是最优的(尽管我有待纠正)。

以上是关于如何找到给定 N 切割的无限杆的最大段数的主要内容,如果未能解决你的问题,请参考以下文章

给定网络是不是具有唯一的最小切割?

钢条切割问题求解方法及相关思考

动态规划切棍子问题再思考

最大流量和最小切割中的多个源和汇

如何使用最大流量算法在图上找到最小割?

动态规划学习笔记--对于钢条切割方案的思考