[英]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.