Algorithm for Permutation with Buckets

吃可爱长大的小学妹 提交于 2021-02-10 17:54:34

问题


I am looking for an algorithm which works like this

permutateBuckets([A,B,C])

and gives the following result:

[ [[A,B,C]],
  [[A,B],[C]], [[A,C],[B]], [[B,C],[A]], [[A],[B,C]], [[B],[A,C]], [[C],[A,B]],
  [[A],[B],[C]], [[A],[C],[B]], [[B],[A],[C]], [[B],[C],[A]], [[C],[A],[B]], [[C],[B],[A]]
]

In general:

The permutation for [1,2,...,n] should include any possible arrangements of 1 up to n buckets that contain the input values, order of values within buckets is not relevant (e.g. [1,2] equals [2,1]), only the order of the containing buckets matters (e.g. [[1,2],[3]] is different than [[3],[1,2]] ).

Each input element has to be in exactly one bucket for a result to be valid (e.g. an input of [1,2] cannot give [[1]] (missing 2), or [[1,2],[1]] (1 appears twice) as output).


回答1:


The simplest approach is recursive:

 Make [[A]] list
 Insert new item in all possible places - 
    before current sublists
    between all sublists
    after current sublists
    into every sublist

For example, list [[B][A]] produces 5 new lists with item C - places to insert C are:

  [   [B]   [A]   ]
    ^  ^  ^  ^  ^

and three level-2 lists [[A],[B]], [[B],[A]], [[A,B]] produce 5+5+3=13 level-3 lists.

Alternative way:
Generate all n-length nondecreasing sequences from 1...1 to 1..n and generate unique permutations for every sequence. Values on these permutations correspond to the bucket number for every item. For example, 122 sequence gives 3 permutations that corresponds to distributions:

1 2 2     [1],[2, 3] 
2 1 2     [2],[1, 3] 
2 2 1     [3],[1, 2]

In any case number of distributions rises very quickly (ordered Bell numbers 1, 3, 13, 75, 541, 4683, 47293, 545835, 7087261, 102247563...)

Implementation of iterative approach in Delphi (full FP-compatible code at ideone)

 procedure GenDistributions(N: Integer);
  var
    seq, t, i, mx: Integer;
    Data: array of Byte;
    Dist: TBytes2D;
  begin
    SetLength(Data, N);

    //there are n-1 places for incrementing
    //so 2^(n-1) possible sequences
    for seq := 0 to 1 shl (N - 1) - 1 do begin
      t := seq;
      mx := 0;
      Data[0] := mx;
      for i := 1 to N - 1 do begin
        mx := mx + (t and 1); //check for the lowest bit
        Data[i] := mx;
        t := t shr 1;
      end;

      //here Data contains nondecreasing sequence 0..mx, increment is 0 or 1
      //Data[i] corresponds to the number of sublist which item i belongs to

      repeat
        Dist := nil;
        SetLength(Dist, mx + 1); // reset result array into [][][] state

        for i := 0 to N - 1 do
          Dist[Data[i]] := Dist[Data[i]] + [i]; //add item to calculated sublist

        PrintOut(Dist);
      until not NextPerm(Data);  //generates next permutation if possible

    end;

And now Python recursive implementation (ideone)

import copy
cnt = 0

def ModifySublist(Ls, idx, value):
    res = copy.deepcopy(Ls)
    res[idx].append(value)
    return res

def InsertSublist(Ls, idx, value):
    res = copy.deepcopy(Ls)
    res.insert(idx, [value])
    return res

def GenDists(AList, Level, Limit):
    global cnt
    if (Level==Limit):
        print( AList)
        cnt += 1
    else:
        for i in range(len(AList)):
            GenDists(ModifySublist(AList, i, Level), Level + 1, Limit)
            GenDists(InsertSublist(AList, i, Level), Level + 1, Limit)
        GenDists(InsertSublist(AList, len(AList), Level), Level + 1, Limit)

GenDists([], 0, 3)
print(cnt)

Edit: @mhmnn cloned this code in JavaScript using custom items for output.



来源:https://stackoverflow.com/questions/47376466/algorithm-for-permutation-with-buckets

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!