簡體   English   中英

最大不交集的集合

[英]Collection of maximum disjoint sets

給定一組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)。 不知道這是否有意義,但請告訴我您的想法!

如果三個數字始終是連續的,則可以使用簡單的動態編程解決方案(使用遞歸公式使用數字1..i計算可以放置的最大集合)。

但是,如果此約束並不總是正確的,那么這個問題就很難解決。 NP很難,因為它可以用來解決NP完全3維匹配問題

例如,假設我們匹配X,Y,Z中的元素。 我們可以使用數字1 .. | X |為每個允許的匹配構建集合。 在第一位置| X | +1 .. | X | + | Y | 在第二位置和| X | + | Y | .. | X | + | Y | + | Z | 在第三位置。 一旦構建了這些集合,我們就可以使用一種算法來解決三維匹配問題。

貪婪會做。 請注意,三胞胎實際上是間隔,中間數無所謂,只有開始/結束才有意義(即在[start, whatever, end]忽略whatever

O(N log(N))貪婪解

  1. 使用以下關系順序對時間間隔進行排序:

    • 將具有較高末端的末端放置到末端(即“ [開始i ,末端i ] <[開始j ,末端j ]”,如果“末端i <末端j
    • 在相等的兩端,較長的那個較高(即“ [[start i ,end] <[start j ]”,如果“ start j <start i “)
  2. 拿起一疊並推入最后一段

  3. 向下掃描排序的間隔( k索引為當前)

    • 如果“ start k ”高於“ start stack-top ”(即,curr間隔讓它前面有更多空間),則彈出堆棧頂部並推動當前堆棧。
    • 如果“ start stack-top ”>“ end k ”-當前的棧頂不與棧頂重疊-只需將當前間隔推入棧中(是解決方案的一部分)。
    • 否則,請忽略當前間隔(到目前為止,我們擁有最佳解決方案的重疊;貪婪的我們不想失去它)

最后,您將獲得堆棧中不重疊段的最大數量,最左側在最上面-這是O(N)的空間復雜度。
如果您只需要計算它們,請注意比較中只涉及堆棧的頂部,因此您只需要記住堆棧的頂部(每次您彈出/推入時,將“堆棧頂部”替換為當前count保持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),count = 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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM