我想写一个R代码来生成方程x1 + x2 + ... + xm = n的所有不同解,其中n是正整数,xi> = 0,是非负整数。
我为此目的编写了一个R代码,但我不喜欢它的运行时间。此外,它对于相对较大的m和n值不起作用,如n = m = 10。 我的代码如下。
A<-matrix(ncol=m,nrow=choose((n+m-1),(m-1)))
a<-1
for (h in 1:((n+1)^m)) {
l <- rep(NA, m)
for (il in 1:m) {
l[il] <- (((h-1) %/% ((n+1)^(il-1))) %% (n+1)) + 1
l[il]<-l[il]-1
}
if(sum(l)==n) { A[a,]<-l;a<-a+1}
}
A
任何人都知道找到该等式的解决方案的更有效方法吗? 谢谢。
答案 0 :(得分:1)
您似乎正在经历更多数字组合而非需要。当您输入代码时,n + m - 1选择m - 1表示将满足此类问题的解决方案的数量。想想为什么它的工作原理如下:我们想把n分成m组。如果我们将n个元素并排排列,我们需要制作m-1个印章来创建m个组。我们可以考虑每个印章作为它自己的元素。让我们用n = 8,m = 5来具体考虑它。就好像我们需要将8个a分成5组(4个剁,用“/”表示)。这就像我们有一排12个空格一样,我们不得不在行中加上8个和4个。示例输出可以是:
a a / / a / a a a a / a
如果我们找到斜杠的索引之间的差异并减去一个(并且假设在0和n + m的外部索引上有2个额外的斜杠),我们可以找到每个解决方案。对于上面的例子,5个数字将是2(3 - 0 - 1),0(4 - 3 - 1),1(6 - 4 - 1),4(11 - 6 - 1)和1(13 - 11 - 1)。因此,如果我们生成所有(n + m - 1)选择(m - 1)结果,我们可以做简单的减法,而不需要担心任何额外的组合。
我们也可以使用combinations()
库中的gtools
函数来使用代码模拟这一点。
library(gtools)
nums <- rep(0, m)
combs <- combinations(n + m - 1, m - 1)
for(i in 1:choose(n + m - 1,m - 1)){
for(j in 1:m){
#edge case for beginning
if(j == 1){
nums[j] <- combs[i, j] - 1
}
#edge case for end
else if(j == m){
nums[j] <- n + m - combs[i, j-1] - 1
}
else {
nums[j] <- combs[i, j] - combs[i, j-1] - 1
}
}
A[i,] <- nums
}
如果你想进一步提高速度,可以将内部for循环放在一个函数中,该函数接受组合矩阵,n和m的一行,并返回所需解决方案输出的单行。然后,您可以对该函数使用apply函数:
rowSummer <- function(spaces, size, max){
nums <- rep(0, size)
for(j in 1:size){
if(j == 1){
nums[j] <- spaces[j] - 1
}
else if(j == size){
nums[j] <- max - spaces[j-1] - 1
}
else {
nums[j] <- spaces[j] - spaces[j-1] - 1
}
}
nums
}
combs <- combinations(n+m-1, m-1)
A <- apply(combs, 1, rowSummer, size=m, max=n+m)
t(A)
但是,上面的原始解决方案只需通过必要的组合即可加快速度。