【问题标题】:list all permutations of k numbers, taken from 0:k, that sums to k列出 k 个数字的所有排列,取自 0:k,总和为 k
【发布时间】:2014-11-19 23:37:15
【问题描述】:

这个问题与另一个问题R:sample() 密切相关。我想在 R 中找到一种方法来列出 k 个数字的所有排列,总和为 k,其中每个数字都是从 0:k 中选择的。如果 k=7,我可以从 0,1,...,7 中选择 7 个数字。一个可行的解决方案是 0,1,2,3,1,0,0 另一个是 1,1,1,1,1,1,1。我不想生成所有排列,因为如果 k 比 7 大得多,就会爆炸。

当然,在 k=7 示例中,我可以使用以下内容:

perms7<-matrix(numeric(7*1716),ncol=7) 
count=0
for(i in 0:7)
    for(j in 0:(7-i))
        for(k in 0:(7-i-j))
            for(l in 0:(7-i-j-k))
                for(n in 0:(7-i-j-k-l))
                    for(m in 0:(7-i-j-k-l-n)){
                            res<-7-i-j-k-l-n-m
                            count<-count+1
                            perms7[count,]<-c(i,j,k,l,n,m,res)
                        }
head(perms7,10)  

但是我如何推广这种方法来解释任何 k 而不必编写 (k-1) 循环? 我试图想出一个递归方案:

perms7<-matrix(numeric(7*1716),ncol=7) #store solutions (adjustable size later)
k<-7 #size of interest
d<-0 #depth
count=0 #count of permutations
rec<-function(j,d,a){
    a<-a-j #max loop
    d<-d+1 #depth (posistion)
    for(i in 0:a ) {
        if(d<(k-1)) rec(i,d,a)
        count<<-count+1
        perms7[count,d]<<-i
        perms7[count,k]<<-k-sum(perms7[count,-k])
    }
}
rec(0,0,k)

但是卡住了,我不太确定这是正确的方法。想知道是否有任何“神奇”的 R 函数可以很好地解决这个(虽然非常具体)问题,或者只是其中的一部分。

在 k=7 的情况下,所有 2.097.152 排列和总和为 k=7 的 1.716 可以通过以下方式找到:

library(gtools)
k=7
perms <- permutations(k+1, k, 0:k, repeats.allowed=T) #all permutations
perms.k <- perms[rowSums(perms) == k,] #permutations which sums to k

对于 k=8,有 43.046.721 个排列,但我只想列出 6.435。 非常感谢任何帮助!

【问题讨论】:

  • 我相信这与河内塔问题有关。包funref 具有解决此问题的功能。
  • 我不明白这与河内塔问题有什么关系,您能详细说明一下吗?基本上我只需要计算 Z^k 中超平面的基数。
  • 它是k-tile,k-peg ToH的所有可能状态的空间。显然,ToH 的最佳解决方案不会寻求遍历所有状态,但如果您寻找最大次优解决方案,您应该会得到答案。
  • 啊,我明白了你的想法,其中包含 k-tiles、k-pegs 的 ToH,并且瓷砖之间没有区别。但后来我又回到了以某种方式列出这个空间的问题,我将研究推荐的软件包以寻求解决方案。谢谢。
  • 顺便说一句,这些不是“排列”,因为严格来说,您必须排列给定集合的所有元素。只是在这里吹毛求疵的数学家。您正在做的是选择“多集”子集的各种排列,其中包含每个 0:7 的七个重复 :-)

标签: r loops recursion permutation


【解决方案1】:

有一个包...

require( partitions )
parts(7)                                 
#[1,] 7 6 5 5 4 4 4 3 3 3 3 2 2 2 1
#[2,] 0 1 2 1 3 2 1 3 2 2 1 2 2 1 1
#[3,] 0 0 0 1 0 1 1 1 2 1 1 2 1 1 1
#[4,] 0 0 0 0 0 0 1 0 0 1 1 1 1 1 1
#[5,] 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1
#[6,] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
#[7,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

您似乎在寻找compositions()。例如对于k=4

parts(4)

#[1,] 4 3 2 2 1
#[2,] 0 1 2 1 1
#[3,] 0 0 0 1 1
#[4,] 0 0 0 0 1

compositions(4,4)                                                                          
#[1,] 4 3 2 1 0 3 2 1 0 2 1 0 1 0 0 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 4 0 1 2 3 0 1 2 0 1 0 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 0 1 1 1 1 2 2 2 3 3 4 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 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 4

只是为了检查你的数学...... :-)

ncol(compositions(8,8))
#[1] 6435

【讨论】:

  • 这很整洁。我将研究 composition() 是如何工作的,以确保它不只是计算所有排列然后是子集。谢谢!
  • @J.R.非常快!您需要下载源代码,因为我认为您需要检查 pacakge 中的 C 函数 allblockparts
  • 是的,它工作得很好,所以我很有信心它不会首先列出所有排列!您应该考虑将其添加为开头提到的链接问题的解决方案。我会看看allblockparts。再次感谢您!
  • @J.R.看起来 Josh O'Brien 已经在 cmets 中做到了。不过,请随意添加答案。鼓励这样做。
  • 酷 - 被介绍给我还没见过的包总是很有趣。
猜你喜欢
  • 1970-01-01
  • 2017-01-18
  • 2015-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-12
  • 2011-02-21
  • 1970-01-01
相关资源
最近更新 更多