Java - итеративно генерировать powerset в определенном порядке - PullRequest
0 голосов
/ 24 февраля 2019

Мне нужно итеративно генерировать powerset большого набора в определенном порядке.Итеративно я имею в виду, что при каждом вызове getNext () (или аналогичного) я получаю следующий элемент powerset в определенном порядке.Предварительный расчет и хранение всего блока питания не вариант, так как он будет слишком большим;Я говорю о powerset набора из 200 предметов.Вместо этого конкретный порядок позволит мне оптимизировать и пропустить вперед, когда появятся «неинтересные» элементы powerset.

Указанный порядок выглядит следующим образом, для упорядоченного набора из пяти элементов с 1, представляющего включение элемента в блок питанияэлемент (слева направо, сверху вниз):

00000 10000 11000 11100 11110 11111
      01000 10100 11010 11101
      00100 10010 11001 11011
      00010 10001 10110 10111
      00001 01100 10101 01111
            01010 10011
            01001 01110
            00110 01101
            00101 01011
            00011 00111

С «пропуском вперед» я имею в виду, что если я, например, определю, что 10010 не удовлетворяет некоторому критерию, я не знаю, что ни один изследующие элементы powerset с двумя единицами будут соответствовать этому критерию, поэтому я могу перейти к рассмотрению элементов powerset с тремя единицами.

Я реализовал частично работающее решение, используя смещение частей элементов powerset, ноДалеко не удалось разобраться в логике правильной обработки всего этого.Очевидно, что множества с нулями 1 и пятью 1, а также одним 1 и четырьмя 1 являются соответствующими зеркальными изображениями друг друга, интересными случаями являются средние выше, с двумя 1 и тремя 1.Любая помощь будет оценена.

1 Ответ

0 голосов
/ 27 февраля 2019

Думая об этом правильно, это становится довольно тривиальным.

/***************** PowerSetIterator.java **********************************/
/**
 * @author OppfinnarJocke
 */
/* This class iteratively generates the power set (except for the empty set)
 * First it generates all subsets of num_slots 1, then of num_slots 2, ... 
  * then of num_slots len (of which there is only one)
 */
public class PowerSetIterator
{
    private final int len;
    private final int[] slots;
    private int num_slots;

    public PowerSetIterator(final int len)
    {
        this.len = len;
        this.slots = new int[this.len];
        this.num_slots = 0;
    }

    public int[] next()
    {
        recurse(this.num_slots);

        return this.slots;
    }

    private int recurse(final int right_slot)
    {       
        final int this_slot = right_slot - 1;
        //if(this_slot < 0)
        //  return this.len - this.num_slots;
        assert this_slot >= 0 : "index cannot be < 0";
        // Cannot really grok why this never happens...

        if(!this.isExhausted(this_slot))
            this.slots[this_slot]++;
        else
            this.slots[this_slot] = recurse(this_slot);

        return this.slots[this_slot] + 1;
    }

    /**
     * Skips to next num_slots, and sets up for subsequent iterations
     *
     * @return false if num_slots >= len, that is, if we have already exhausted the powerset generation
     */
    public final boolean nextSize()
    {
        if(this.num_slots >= this.len)
            return false;

        this.num_slots++;
        for(int i = 0; i < this.num_slots; i++)
            this.slots[i] = i;

        return true;
    }

    /**
     * Checks if the last num_slots elements have all reached their end indexes.
     *
     * @return true if the powerset for this num_slots has been enumerated
     */
    public boolean doneWithThisSize()
    {
        for(int i = 0; i < this.num_slots; i++)
            if(isExhausted(i) == false)
                return false;

        return true;
    }

    /**
     * We are finished when len number of slots have been occupied. 
     * 
     * @return true if all sizes and combinations have been exhausted
     */
    public boolean isFinished()
    {
        return this.num_slots == this.len;
    }

    /**
     * Determine whether this slot has exhausted its indexes. Slots hold values between 
     * slot_index <= slots[slot_index] <= num_items - num_slots + slot_index
     * 
     * @param slot_index Index of the slot to check
     * @return true if the slot at slot_index is at or beyond its range
     */
    private boolean isExhausted(final int slot_index)
    {
        assert slot_index <= this.slots[slot_index] : "Slot value below slot_index";

        return this.slots[slot_index] >= this.len - this.num_slots + slot_index;
    }

    @Override
    public String toString()
    {
        StringBuilder buf = new StringBuilder();
        for(int i = 0; i < this.num_slots; i++)
        {
            buf.append(this.slots[i]);
            buf.append(',');
        }

        buf.setLength(buf.length()-1);

        return buf.toString();
    }

    public String toBitString()
    {
        final char[] charray = new char[this.len];
        java.util.Arrays.fill(charray, '0');

        // Fill the correct postions with 1's
        for(int i = 0; i < this.num_slots; i++)
        {
            final int index = this.slots[i];
            charray[index] = '1';
        }

        final String bit_string = new String(charray);
        return bit_string;
    }


    public static void main(String[] args)
    {
        final int LENGTH = 5;
        PowerSetIterator set_it = new PowerSetIterator(LENGTH);

        while(!set_it.isFinished())
        {
            set_it.nextSize();
            print_it(set_it);

            while(!set_it.doneWithThisSize())
            {
                set_it.next();
                print_it(set_it);
            }
        }
    }

    private static void print_it(final PowerSetIterator set_it)
    {
        System.out.println("set_it.toString() = " + set_it.toString());
        System.out.println("set_it.toBitString() = " + set_it.toBitString());       
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...