[英]Generating all permutations of N balls in M bins
I want to generate a set of permutations of n
balls in m
bins.我想在m
个 bin 中生成一组n
球的排列。 The following set of nested lists generates those permutations.以下嵌套列表集生成这些排列。
n <- 3
m <- 4
v <- rep(0,m)
for (i in n:0){
for (j in (n-sum(i)):0){
for (k in (n-sum(i,j)):0){
for (l in (n - sum(i,j,k)):0){
v <- c(i,j,k,l)
print(v)
if (sum(v) == n){ break }
}
}
}
}
Which prints the solution:哪个打印解决方案:
[1] 3 0 0 0
[1] 2 1 0 0
[1] 2 0 1 0
[1] 2 0 0 1
[1] 1 2 0 0
[1] 1 1 1 0
[1] 1 1 0 1
[1] 1 0 2 0
[1] 1 0 1 1
[1] 1 0 0 2
[1] 0 3 0 0
[1] 0 2 1 0
[1] 0 2 0 1
[1] 0 1 2 0
[1] 0 1 1 1
[1] 0 1 0 2
[1] 0 0 3 0
[1] 0 0 2 1
[1] 0 0 1 2
[1] 0 0 0 3
The total number of permutations will be choose(n+m-1,m-1)
, and the order of the permutations does not matter to me.排列的总数将是choose(n+m-1,m-1)
,排列的顺序对我来说并不重要。 But I am having a hard time making this into a function that can take an arbitrary number of bins.但是我很难把它变成一个 function 可以带任意数量的垃圾箱。 (I won't spoil the well with my attempts, it is just jumble of nested loops though.) So if someone more saavy than me could translate the nested loops above into a function I would appreciate it. (我不会用我的尝试破坏这口井,不过它只是嵌套循环的混乱。)因此,如果有人比我更精明,可以将上面的嵌套循环转换为 function,我将不胜感激。
Or if there is already a function available to conduct this type of permutation (or a different algorithm to follow) I would appreciate being told about it.或者,如果已经有一个 function 可用于进行这种类型的排列(或要遵循的不同算法),我将不胜感激。 I would prefer an approach that does not generate superfluous permutations (here ones that do not add up to n
) and then discards them, but for small problems like this a solution that does that would be acceptable.我更喜欢一种不会产生多余排列的方法(这里的排列不等于n
)然后丢弃它们,但是对于像这样的小问题,这样做的解决方案是可以接受的。
library(partitions)
compositions(3,4)
# [1,] 3 2 1 0 2 1 0 1 0 0 2 1 0 1 0 0 1 0 0 0
# [2,] 0 1 2 3 0 1 2 0 1 0 0 1 2 0 1 0 0 1 0 0
# [3,] 0 0 0 0 1 1 1 2 2 3 0 0 0 1 1 2 0 0 1 0
# [4,] 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 2 2 2 3
The following gives a slightly different but equivalent answer by using a more general package iterpc
以下通过使用更通用的包iterpc
给出了稍微不同但相当的答案
m = 4; n = 3
library(iterpc)
I = iterpc(m, n, replace=T)
getall(I)
The output is the bin numbers for the n balls. 输出是n个球的bin编号。
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
....
....
[18,] 3 3 4
[19,] 3 4 4
[20,] 4 4 4
The first line means that the 3 balls are all from bin 1 while the last line means that the 3 balls are all from bin 4. 第一行表示3个球全部来自箱1,而最后一行表示3个球全部来自箱4。
You can easily produce your desired result by counting numbers of 1, 2, 3 and 4's. 您可以通过计算1,2,3和4的数字轻松生成所需的结果。 And you can also make use of the iterator to generate the result sequentially. 您还可以使用迭代器按顺序生成结果。
count <- function(x){
as.numeric(table(factor(x, levels=1:m)))
}
I = iterpc(m, n, replace=T)
> count(getnext(I))
[1] 3 0 0 0
> count(getnext(I))
[1] 2 1 0 0
> count(getnext(I))
[1] 2 0 1 0
> count(getnext(I))
[1] 2 0 0 1
Using the excellent RccpAlgos package :使用优秀的RccpAlgos package :
library(RcppAlgos)
permuteGeneral(0:(n + 1), m,
constraintFun = "sum",
comparisonFun = "==",
limitConstraints = n,
repetition = TRUE)
[,1] [,2] [,3] [,4]
[1,] 0 0 0 3
[2,] 0 0 3 0
[3,] 0 3 0 0
[4,] 3 0 0 0
[5,] 0 0 1 2
[6,] 0 0 2 1
[7,] 0 1 0 2
[8,] 0 1 2 0
[9,] 0 2 0 1
[10,] 0 2 1 0
[11,] 1 0 0 2
[12,] 1 0 2 0
[13,] 1 2 0 0
[14,] 2 0 0 1
[15,] 2 0 1 0
[16,] 2 1 0 0
[17,] 0 1 1 1
[18,] 1 0 1 1
[19,] 1 1 0 1
[20,] 1 1 1 0
Given that there are dedicated functions for integer partition and composition in the package, this may seem unnecessarily convoluted.鉴于 package 中有integer 分区和组合的专用函数,这可能看起来不必要地令人费解。 However, here's a reply from the package author:不过,这里是 package 作者的回复:
Currently your workaround is the best solution.目前,您的解决方法是最好的解决方案。 When I initially wrote this code, I wasn't aware of the need for weak compositions (where 0 is treated like other digits).当我最初编写此代码时,我没有意识到需要弱组合(其中 0 被视为其他数字)。 In the next release, you will have access to a suite of composition functions where
weak
will be a parameter.在下一个版本中,您将可以访问一组以weak
为参数的组合函数。 The interface in general is much nicer than the more generalpermuteGeneral
interface一般的接口比更通用的permuteGeneral
接口好得多
Thus, anticipate an update of this answer!因此,期待这个答案的更新!
This can be done pretty easily in R - I see a lot of complicated algorithms out there, but it can be done by shifting bars.这可以在 R 中很容易地完成 - 我看到很多复杂的算法,但可以通过移动条来完成。 We keep track of the locations of partitions (bars) rather than how many are in each bin.我们跟踪分区(条)的位置,而不是每个箱中有多少。 If there are 3 objects that makes 3 bar positions:如果有 3 个对象构成 3 个条形位置:
objects O O O
bar position 0 1 2 3
For example, if we have N=3 and K=4 bins, we will have K-1=3 bars.例如,如果我们有 N=3 和 K=4 个柱,我们将有 K-1=3 个柱。 Begin with all bars position 0从所有条开始 position 0
|||OOO |||OOO
In other words, all objects are in bin 4. The algorithm goes like this:换句话说,所有对象都在 bin 4 中。算法如下:
This will iterate through every partitioning of N objects into K bins.这将遍历 N 个对象的每个分区到 K 个 bin。
and so on.等等。
N=3
K=4
k=K-1
bars=rep(0,k)
bars[k]=-1 #so bars should be a vector of k-1 0s and then a -1;
while(bars[1]<N){ #if the first bar is at position N then we're done
for(j in k:1){ #go backwards through bars
if(bars[j]<N){ #the first bar that is not in the final position...
bars[j:k]=bars[j]+1 ##bump it up by 1 and reset all subsequent bars
break
}
}
print(c(bars,N)-c(0,bars))
##this just translates bar positions into bin counts
}
Here is a base R solution that returns a list.这是一个返回列表的基本 R 解决方案。
get_list <- function(M, N) {
# All permutations
perms <- expand.grid(rep(list(0:N), M))
# Keep those meeting constraints
kept <- perms[rowSums(perms) == N,]
# Return as list
if (length(kept) > 1) {
split(kept, seq(nrow(kept)))
} else {
as.list(kept)
}
}
# Compute
get_list(N = 5, M = 1)
#> [[1]]
#> [1] 5
get_list(N = 2, M = 3)
#> $`1`
#> Var1 Var2 Var3
#> 3 2 0 0
#>
#> $`2`
#> Var1 Var2 Var3
#> 5 1 1 0
#>
#> $`3`
#> Var1 Var2 Var3
#> 7 0 2 0
#>
#> $`4`
#> Var1 Var2 Var3
#> 11 1 0 1
#>
#> $`5`
#> Var1 Var2 Var3
#> 13 0 1 1
#>
#> $`6`
#> Var1 Var2 Var3
#> 19 0 0 2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.