简体   繁体   中英

2 power of 77 java Powerset

I have 77 elements n1,n2,n3... etc I need to calculate superset. I used the binary mask algorithme but the number is to big to fit in int. Here is the code:

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;
   } 

I tried to remove the int by using long or double, but nothing worked.

You need a data structure storing binary digits that is 77 digits long. You could use an array of 77 ints and manually increment the array as one big binary number where each element of the array is one bit in your number. I wrote the Increment method below.

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");
}

As noted by commenters, you won't have room to store 2^77 sets. And it will take virtually forever to count up to 2^77.

From the comments it become clear this is to find the maximum clique , so I will now focus on that instead of on the literal question.

First some simple tricks. With backtracking, many branches of the search space can be pruned. The rough idea looks like

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)

This is still the naive version, trying every possible subset. But there are some obvious improvements. For example, there's no point in waiting to test whether the potential clique is actually a clique until the last moment, every subset of nodes that form a clique also form a clique. Adding a node to it that doesn't leave it a clique is pointless. Call this #1. This prunes a lot .

Also, if the current clique plus the nodes that could possible be added to it is less than the best found clique, nothing better can be found in this branch of the search space. There are several different levels of effort you can do here, the simplest is just counting all in the leftover set, but you could go for the biggest clique in that set or something. Anyway I'll show the simple one, call it #2. Now we have something like:

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)

An other option to estimate the size of clique you could build is to use linear programming.

For example, this is an ILP model for max clique:

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

The linear relaxation (ie dropping the last constraint) of that is easy to compute, and you can lazily add the constraints if you want. Obviously there are constraints coming from the clique / banned sets, forcing certain x's to be 1 or 0 respectively. If the objective value of the linear relaxation is not better than your biggest found clique, then you can prune the current branch.

There are an other fun property of that model. If the resulting x has all entries from {0, 0.5, 1}, then you can immediately decide to pick all nodes for which x[i] = 1 to be in your clique, so you can skip a lot of branching in that case. This is probably uncommon high in the search tree, but you can add some Gomory cuts to encourage integrality. Your favourite LP solver may have them built in.

There are more clever tricks here, check the literature.

A completely different way to attack the problem is with SAT, which does not optimize at all, but you can try every size of clique and for every size use SAT to ask whether there is a clique of that size (and if it exists, what it looks like). Actually it's easiest as a Pseudo boolean model:

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

The usual adjacency constraint is trivial to state in pure SAT, the sum constraint is annoying, requiring an addition circuit. That's easy enough to generate, but hard to write out here, not only because it depends on k.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM