【问题标题】:Algorithm for Permutation with Buckets带桶的置换算法
【发布时间】:2017-11-19 11:47:29
【问题描述】:

我正在寻找这样的算法

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 出现两次)作为输出)。

【问题讨论】:

  • 递归方法当然更容易,但可能不是最有效的解决方案。你会对这种递归方法感到满意吗? (我没有解决方案,只是想知道您的期望)。
  • 我还认为递归方法是最有效的方法——递归或顺序都可以。

标签: algorithm permutation


【解决方案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个三级列表。

替代方式:
生成从 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 中实现迭代方法(在ideone 上与 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 在JavaScript 中克隆了这段代码,使用自定义项进行输出。

【讨论】:

  • 明天我将尝试编写该方法并发布我的结果,谢谢!
  • 我根据您的 Python 代码在 JavaScript 中实现了它,并通过接受具有排列值的数组来扩展它。代码可以在这里找到:jsfiddle.net/gvf2dg9e 随意将代码添加到您的答案中以获得更多可见性 - 请注意 Lodash.js 用于 cloneDeep 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
  • 1970-01-01
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多