【问题标题】:Collection of maximum disjoint sets最大不相交集的集合
【发布时间】:2016-12-09 21:25:37
【问题描述】:

给定一组 3 个数字的集合,找出最大的不相交集合。例如,令 C = {(3,4,5), (4,5,6), (1,2,3), (6,9,10), (7,8,9)}。此输入应返回 3,因为最大不相交集是 {(1,2,3), (4,5,6), (7,8,9)}。如何编写一个程序来输出最大不相交集的集合?

我考虑过从选择所有 5 个集合开始。然后,查看每个集合,看看删除该元素是否会影响其余集合。如果我们拿走 (3,4,5),它将允许我们保留 (4,5,6) 和 (1,2,3)。因此,它的净收益是+1。我们应该将其从最终列表中删除。然后,如果我们拿走 (4,5,6),它将允许我们保留 (6,9,10)。净收益为 0,所以不要删除它。删除 (1,2,3) 不会有任何影响。不要删除它。删除 (6,9,10) 将允许我们保留 (7,8,9)。不确定这是否有意义,但请告诉我您的想法!

【问题讨论】:

  • 欢迎来到stackoverflow。 Stackoverflow 是一个询问特定编程问题的地方。一个更好的问题将包括您尝试使用您有疑问的特定部分的编码解决方案。你的问题非常广泛。请尝试缩小范围。看看What topics can I ask about here?
  • 最大不相交集 - 是指覆盖大多数元素,还是此类集的最大绝对数量?
  • 这些集合总是由 3 个连续数字组成吗?相比之下,是否应该期待像 {2,3,5} 这样的 3 数字集?
  • @amit 表示第二个 -- 此类集合的最大数量
  • @AdrianColomitchi 他们不是连续的!

标签: algorithm


【解决方案1】:

如果三个数字总是连续的,那么这有一个简单的动态规划解决方案(使用递归公式计算可以使用数字 1..i 放置的最大集合)。

但是,如果这个约束并不总是正确的,那么这个问题就是 NP 难题。 它是 NP 难的,因为它可以用来解决 NP-complete 3-dimensional matching problem

例如,假设我们要匹配 X,Y,Z 中的元素。我们可以使用数字 1..|X| 为每个允许的匹配构造集合。在第一个位置,|X|+1..|X|+|Y|在第二个位置和 |X|+|Y|..|X|+|Y|+|Z|在第三位。一旦我们构建了这些集合,我们就可以使用算法来解决 3 维匹配问题。

【讨论】:

  • 您能帮我解决一下 3 维匹配问题吗?在我的情况下,X、Y、Z 是什么?
  • 不,这不是 NP 难的。这是 N log(N) 和 greedy
【解决方案2】:

贪婪会做。请注意,三连音实际上是间隔,中间数字无关紧要,只有开始/结束的数字才重要(即在 [start, whatever, end] 中忽略 whatever

O(N log(N)) greedy solution

  1. 使用关系顺序对区间进行排序:

    • 将具有较高端的那些放在末尾(即 "[starti, endi] j, end j]" iff "endij"
    • 在相等的两端,较长的更高(即 "[starti, end] j]" iff "startj i" )
  2. 取一个堆栈并将最后一段压入

  3. 向下扫描已排序的区间(k 索引是当前的)

    • 如果“startk”高于“startstack-top”(即当前间隔在其前面留出更多空间),弹出顶部堆栈并推送当前堆栈。
    • 如果 "startstack-top" > "endk" - 当前不与堆栈顶部重叠 - 只需将当前间隔推入堆栈 (是解决方案的一部分)。
    • 否则,忽略当前间隔(与我们目前拥有的最佳解决方案重叠;贪婪我们不想失去它)

最后,您将在堆栈中获得最大数量的非重叠段,最左边的在顶部 - 这是 O(N) 的空间复杂度。
如果您只需要计算它们,请注意只有堆栈顶部参与比较,因此您只需要记住堆栈顶部(每次弹出/推送时将“堆栈顶部”替换为当前一个并让count 不变;每次只推送替换“栈顶”并增加计数)。所以只计算的空间复杂度是O(1)。


你的例子:

  1. 在排序步骤之后,您的区间为 {(1,2,3), (3,4,5), (4,5,6), (7,8,9), ( 6,9,10)}

  2. 栈顶 (6,9,10) - 计数 1。以下所有步骤都是循环的展开。

  3. 采用 (7,8,9) - 更保守的开始,驱逐栈顶(与旧的一起出)推当前(与新的一起) - 栈顶 (7,8,9),计数=1。

  4. (4,5,6) - 在栈顶开始之前结束,收集它 - 栈顶 (4,5,6), count=2;

  5. (3,4,5) - 较小的开始,但与堆栈顶部重叠。贪婪 - 忽略/丢弃。栈顶(4,5,6),count=2;

  6. (1,2,3) - 在栈顶开始之前结束,收集它 - 栈顶 (1,2,3), count=3;

向下循环结束,堆栈从上到下读取:{(1,2,3}, (4,5,6), (7,8,9)},计数为 3。


C++(未测试

struct interval { int s; int e; }

struct comparator {
  bool operator(const interval& i1, const interval& i2) const {
    int i=i1.e-i2.e; // higher ends placed last
    if(0==i) { // higher length/lower starts will be higher
      i=i2.s-i1.s;
    }
    return i<0;
  }
}

int count_intervals(std::vector<interval>& sets) {
  if(sets.empty()) return 0;

  comparator comp;
  std::sort(sets.begin(), sets.end(), comp);

  /* if you need the solution as well, use a stack */
  // std::stack<std::vector> solution;
  interval& stack_top=sets[sets.size()-1]; // solution.push(stack_top);
  int count=1; // we have at least one in the stack
  for(int i=sets.size()-2; i>=0; i--) {
    interval& curr=sets[i];
    if(curr.s > stack_top) { // a better one, lets more room in front
       stack_top=curr; // solution.pop(); solution.push(curr);
    }
    else if(curr.e < stack_top.s) {
      stack_top=curr; // solution.push(curr);
      count++;
    }
  }
  // if you need the solution, arrange the params of the function to return it
  return count;
}

【讨论】:

  • 采用一套系统,其中只有 2 套。例如,S={{1,3,6},{2,4,8}}。即使在这些简单的情况下,这也不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多