簡體   English   中英

2 Java Power Power 77的力量

[英]2 power of 77 java Powerset

我有77個元素n1,n2,n3 ...等等,我需要計算超集。 我使用了二進制掩碼算法,但數量很大以適合int。 這是代碼:

private static Vector powerset(String[] set) {

       //create the empty power set
       Vector power = new Vector();

       //get the number of elements in the set
       int elements = set.length;

       //the number of members of a power set is 2^n
       int powerElements = (int) Math.pow(2,elements);

       //run a binary counter for the number of power elements
       for (int i = 0; i < powerElements; i++) {

           //convert the binary number to a string containing n digits
           String binary = intToBinary(i, elements);

           //create a new set
           Vector innerSet = new Vector();

           //convert each digit in the current binary number to the corresponding element
            //in the given set
           for (int j = 0; j < binary.length(); j++) {
               if (binary.charAt(j) == '1')
                   innerSet.add(set[j]);
           }

           //add the new set to the power set
           power.add(innerSet); 
       }
       return power;
   }
   private static String intToBinary(int binary, int digits) {

       String temp = Integer.toBinaryString(binary);
       int foundDigits = temp.length();
       String returner = temp;
       for (int i = foundDigits; i < digits; i++) {
           returner = "0" + returner;
       }

       return returner;
   } 

我試圖通過使用long或double來刪除int,但沒有任何效果。

您需要一個存儲77位長的二進制數字的數據結構。 您可以使用77個整數的數組,並手動將其遞增為一個大的二進制數字,其中數組的每個元素在數字中都為一位。 我在下面編寫了Increment方法。

int[] num = new int[77];
for (int i = 0; i < 77; i++) num[i]= 0;
//create a new set
for (int i = 0; i < powerElements; i++) {
    Vector innerSet = new Vector();

    for (int j = 0; j < 77; j++) {
        if (num[i] == 1)
            innerSet.add(set[j]); 
    }
    Increment(num);
}

// Increment an array of ints as if it is a binary number. The LSB is the 77th element in the array, index 76.
public void Increment(int[] num) {
    int carry = 1;
    int i = 76;
    while (i > 0) {
        tmp = int[i] + carry;
        if (tmp == 0) break;
        if (tmp == 1) {int[i] = 1; break;}
        carry = 1;
        int[i] = 0;
        i--;
    }
    if (carry == 1) throw new Exception("Overflow");
}

正如評論者所指出的那樣,您將沒有空間存儲2 ^ 77套。 實際上,要計算2 ^ 77幾乎是永遠的。

從評論中可以很明顯地看出這是找到最大的集團 ,所以我現在將重點放在這個問題上,而不是字面上的問題。

首先是一些簡單的技巧。 通過回溯,可以修剪搜索空間的許多分支。 大概的想法是

findMaxClique(clique, banned, graph):
    if clique ∪ banned is everything:
        if isclique(clique) and size(clique) > size(bestFound):
            bestFound = clique
        return
    for each node n not in clique ∪ banned:
        try findMaxClique(clique + n, banned, graph)
        try findMaxClique(clique, banned + n, graph)

這仍然是天真的版本,嘗試所有可能的子集。 但是有一些明顯的改進。 例如,沒有必要等到最后一刻才測試潛在的集團是否真正是集團,形成集團的節點的每個子集也都形成集團。 向其添加一個不會使其成組的節點毫無意義。 稱其為#1。 這修剪了很多

同樣,如果當前派系加上可能添加的節點少於找到的最好派系,則在搜索空間的此分支中找不到更好的派系。 您可以在此處進行幾種不同級別的工作,最簡單的方法就是將剩余的工作集中在所有工作中,但是您可以選擇該工作組中最大的工作組。 無論如何,我將展示一個簡單的示例,將其稱為#2。 現在我們有了類似的東西:

findMaxClique(clique, banned, graph):
    if clique ∪ banned is everything:
        if size(clique) > size(bestFound):
            bestFound = clique
        return
    for each node n not in clique ∪ banned:
        if isclique(clique + n):
            try findMaxClique(clique + n, banned, graph)
        notbanned = graph - (banned ∪ n)
        if size(notbanned) >= size(bestFound):
            try findMaxClique(clique, banned + n, graph)

估計您可以建立的集團規模的另一種選擇是使用線性規划。

例如,這是最大集團的ILP模型:

maximize sum x[i]
s.t.
for each i,j that are not adjacent, x[i]+x[j] ≤ 1
x[i] in { 0, 1 }

線性松弛(即刪除最后一個約束)易於計算,並且您可以根據需要延遲添加約束。 顯然, clique / banned集有一些約束,迫使某些x分別為1或0。 如果線性松弛的目標值不比您發現的最大集團好,那么可以修剪當前分支。

該模型還有另一個有趣的特性。 如果所得的x具有{0,0.5,1}中的所有條目,那么您可以立即決定選擇x [i] = 1的所有節點納入您的派系,因此在這種情況下,您可以跳過很多分支。 這在搜索樹中可能並不常見,但是您可以添加一些Gomory削減以鼓勵完整性。 您最喜歡的LP解算器可能內置了它們。

這里還有更多技巧,請查閱文獻。

解決問題的一種完全不同的方法是使用SAT,它根本不會進行優化,但是您可以嘗試各種規模的小集團,對於每種大小,請使用SAT詢問是否存在該大小的小集團(如果存在,請問什么?看起來像)。 實際上,作為偽布爾模型最簡單:

for each i,j that are not adjacent: ¬i + ¬j ≥ 1
sum of everything = k

通常的鄰接約束對於純SAT來說是微不足道的,總和約束很煩人,需要加法電路。 生成起來很容易,但是在這里很難寫出來,不僅因為它取決於k。

暫無
暫無

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

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