最大不相交集的集合

时间:2016-12-09 21:25:38

标签: algorithm

给定一组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)。不确定这是否有意义,但让我知道你的想法!

2 个答案:

答案 0 :(得分: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 |在第三位。一旦我们构造了这些集合,我们就可以使用算法解决这个问题来解决三维匹配问题。

答案 1 :(得分:1)

贪婪会这样做。请注意,三元组实际上是间隔,中间数字无关紧要,只有开始/结束时间(即[start, whatever, end]忽略whatever

O(N log(N)) greedy solution

  1. 使用以下关系顺序对间隔进行排序:

    • 将具有较高端的那些放置到末尾(即“[start i ,end i ]< [start j , end j ]“iff”end i < end j
    • 在相同的末端,较长的那些较高(即“[start i ,end]< [start j ]”iff“start j < start i “)
  2. 抓住一个堆叠并推送

  3. 中的最后一段
  4. 向下扫描已排序的时间间隔(k索引是当前的)

    • 如果“start k ”高于“start stack-top ”(即curr间隔让它前面有更多空间),则弹出顶部堆栈并推送当前的堆栈。
    • 如果“开始 stack-top ”> “end k ” - 当前的一个不与堆栈顶部重叠 - 只需按下堆栈中的当前间隔(是解决方案的一部分)。
    • 否则,忽略当前的间隔(与我们到目前为止的最佳解决方案重叠;贪婪,我们不想失去它)
  5. 最后,您将获得堆叠中非重叠段的最大计数,最左侧位于顶部 - 这是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),计数= 2;

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

    6. (1,2,3) - 比堆栈顶部开始更快结束,收集它 - 堆栈顶部(1,2,3),计数= 3;

    7. 向下循环结束,堆栈从上到下读取:{(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;
      }
      
相关问题