我正在寻找一种像这样工作的算法
permutateBuckets([A,B,C])
并给出以下结果:
[ [[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]]
]
一般来说:
[1,2,...,n]的排列应该包括1到n个包含输入值的桶的任何可能排列,桶内值的顺序是不相关的(例如[1,2]等于[2,1]),只有包含桶的顺序很重要(例如[[1,2],[3]]不同于[[3],[1,2]])。
每个输入元素必须恰好在一个桶中才能使结果有效(例如[1,2]的输入不能给[[1]](缺少2),或[[1,2],[ 1]](1出现两次)作为输出。)
答案 0 :(得分:1)
最简单的方法是递归的:
Make [[A]] list
Insert new item in all possible places -
before current sublists
between all sublists
after current sublists
into every sublist
例如,list [[B][A]]
生成5个带有项目C的新列表 - 要插入C的位置是:
[ [B] [A] ]
^ ^ ^ ^ ^
和三个二级列表[[A],[B]], [[B],[A]], [[A,B]]
生成5 + 5 + 3 = 13个级别3列表。
替代方式:
生成从1 ... 1到1..n的所有n长度非递减序列,并为每个序列生成唯一的排列。
这些排列的值对应于每个项目的桶号。例如,122序列给出3个对应于分布的排列:
1 2 2 [1],[2, 3]
2 1 2 [2],[1, 3]
2 2 1 [3],[1, 2]
在任何情况下,分布数量都会迅速上升(有序的贝尔数1, 3, 13, 75, 541, 4683, 47293, 545835, 7087261, 102247563...
)
在Delphi中实现迭代方法(here处的完全FP兼容代码)
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;
现在Python递归实现(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)
编辑:@mhmnn使用自定义项目在ideone克隆此代码。