简体   繁体   English

在 M 个 bin 中生成 N 个球的所有排列

[英]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 general permuteGeneral 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 中。算法如下:

  1. Find the right-most bar that is not in position N. Increment that bar position by 1, and also collect all bars to the right to that position.找到不在 position N 中的最右边的条。将该条 position 增加 1,并收集该 position 右侧的所有条。
  2. Record the partition记录分区
  3. Go to 1: Repeat until all bars are in position N Go 为 1:重复直到所有条都在 position N

This will iterate through every partitioning of N objects into K bins.这将遍历 N 个对象的每个分区到 K 个 bin。

  1. |||OOO starting permutation; |||OOO 起始排列; bump bar 3凹凸棒 3
  2. ||O|OO bar 3 is in position 1; ||O|OO 条 3 在 position 1 中; bump it撞它
  3. ||OO|O bar 3 is in position 2; ||OO|O 条 3 在 position 2 中; bump it撞它
  4. ||OOO| ||呜呜| bar 3 is in position 3. bar 2 is in position 0;条 3 位于 position 3 中。条 2 位于 position 0 中; bump it and reset bar 3撞它并重置酒吧 3
  5. |O||OO bar 3 is in position 1; |O||OO 条 3 在 position 1 中; bump it撞它
  6. |O|O|O bar 3 is in position 2; |O|O|O 条 3 在 position 2 中; bump it撞它
  7. |O|OO| |O|OO| bar 3 is in position 3. bar 2 is in position 1;条 3 在 position 3 中。条 2 在 position 1 中; bump it and reset bar 3撞它并重置酒吧 3
  8. |OO||O |OO||O

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.

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