繁体   English   中英

有限重复置换算法

[英]Algorithm of Permutation with Limited Repetition

是否有一种算法可以列出所有重复次数有限的排列? 要是有现成的Java库就好了!

假设我们有 3 个项目{A, B, C} 我们想要 2 个项目的排列。 这将是3 P 2

{A, B}
{A, C}
{B, A}
{B, C}
{C, A}
{C, B}

但是如果我们允许最多重复两次。 会怎样? (我真的不知道。)

我试着想象我们从集合{A, A, B, B, C, C}中得到 2 的排列。 应该是6 P 2 = 30。但是我们必须去掉那些重复项。 我是手工算出来的,是9。我不知道怎么从数学上算出9。

{A, A}
{A, B}
{A, C}
{B, B}
{B, A}
{B, C}
{C, C}
{C, A}
{C, B}

(事实上 3 P 2重复 2 不是一个好例子。这是因为排列中只有 2 个元素。因此,无限重复之间没有区别。 4 P 3重复 2 将是一个更好的例子。但是很难列出所有排列。)

一个更好的例子来说明: 4 P 3 of set {A, B, C, D}

{A, B, C}
{A, B, D}
{A, C, B}
{A, C, D}
{A, D, B}
{A, D, C}
... repeat for permutations starting from {B, ... }
... repeat for permutations starting from {C, ... }
... repeat for permutations starting from {D, ... }

4 P 3的集合{A, B, C, D}重复限制为 2:

{A, A, B}
{A, A, C}
{A, A, D}

{A, B, A}
{A, B, B}
{A, B, C}
{A, B, D}

{A, C, A}
{A, C, B}
{A, C, C}
{A, C, D}

{A, D, A}
{A, D, B}
{A, D, C}
{A, D, D}

... repeat for permutations starting from {B, ... }
... repeat for permutations starting from {C, ... }
... repeat for permutations starting from {D, ... }

是一个谈论类似事情的网页。 但它似乎需要n P n (选择所有元素)。 此外,我仍然需要一种算法来生成和列出排列。

感谢您的帮助!


对于编程实现,其实有一种“不聪明”的做法。

对于集合{A, B, C, D} ,保留一个互补数组int used[0, 0, 0, 0] ,这是每个元素被使用的次数。 每次选择一个元素时增加计数,并向前传递数组的副本(向下调用树)。 然后使用此处启发的递归方法,将其更改为允许无限重复(通过从元素集中删除选定的一个),并在for之后添加一个if (used[i] <= LIMIT)检查语句。

这是“不聪明”并且不够好,因为我们需要一个互补数组并且每次都需要检查使用的数字。

我之前在生成集合的所有可能分区时遇到过这个问题。 这与您正在尝试做的事情本质上是相同的概念。 (给定大小的所有组合与该大小的分区集相同)我发现这篇论文提供了一种非常快速的非递归算法来生成这些组合,而无需任何重复以及 C++ 实现。

好吧,这有点晚了,但我在 GitHub 上有一个Java Combinatorics库可以做到这一点。 下面是基本用法:

在您的项目中包含依赖项:

<dependency>
  <groupId>com.xiantrimble.combinatorics</groupId>
  <artifactId>combinatorics</artifactId>
  <version>0.2.0</version>
<dependency>

然后通过从组合工厂获取虚拟集合来迭代排列:

import com.xiantrimble.combinatorics.CombinatoricFactory;
import com.xiantrimble.combinatorics.CombinatoricFactoryImpl;
import com.xiantrimble.combinatorics.Combinatoric;
...
int k = 6;
int[] domain = {1,1,1,1,2,2,2,3,3,4};
// create a factory.
CombinatoricFactory factory = new CombinatoricFactoryImpl();
Combinatoric<Integer> permutations = factory.createPermutations(k,  domain);

for( Integer[] permutation : permutations ) {
  System.out.println(Arrays.toString(permutation));
}

该代码不执行字典顺序,而是旨在尽量减少连续元素之间的变化,因此请记住这一点。 此外,0.3.0-SNAPSHOT 版本也有一些改进,可在 Sonatype 的快照存储库中找到。

请参阅这篇论文,其中找到了答案数量的理论公式。 论文信息为:“Permutations with limited repeats” by Roberto Frucht from Journal of Combinatorial Theory with doi of 10.1016/S0021-9800(66)80025-X

您可以将排列视为二进制进位处理。 例如,二进制的 0000,0001,0010。

 public static int[][] permutation(int size,int carryNum) {
    if(size == 0)
        return new int[0][0];

    int s = size - 1;
    int cNum = carryNum - 1;
    int s1 = 1;
    for(int i=0;i<size;i++){
        s1 = s1 * carryNum ;
    }
    int[][] commands = new int[s1][size];
    for (int i = 1; i < s1; i++) {

        for (int j = s; j >= 0; j--) {
            commands[i][j] = commands[i - 1][j];
        }

        for (int j = s; j >= 0; j--) {
            int last = commands[i][j];
            if ((last + 1) > cNum) {
                commands[i][j] = 0;
            } else {
                commands[i][j] = last + 1;
                break;
            }
        }
    }
    return commands;
}

public static void main(String[] args) {

    int[][] s = permutation(7,3);
    for (int[] command : s) {
        System.out.println(Arrays.toString(command));
    }
}

output result:

[0, 0, 0, 0, 0, 0, 0]

[0, 0, 0, 0, 0, 0, 1]

[0, 0, 0, 0, 0, 0, 2]
          .
          .
          .
[0, 0, 0, 0, 2, 0, 2]

[2, 2, 2, 2, 2, 2, 2]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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