回覆。分区()

时间:2016-05-18 10:13:22

标签: julia combinatorics

为什么

julia> collect(partitions(1,2))
0-element Array{Any,1}

返回而不是

2-element Array{Any,1}:
 [0,1]
 [1,0]

我真的必须

x = collect(partitions(n,m));
y = Array(Int64,length(x),length(x[1]));
for i in 1:length(x)
    for j in 1:length(x[1])
        y[i,j] = x[i][j];
    end
end

将结果转换为二维数组?

4 个答案:

答案 0 :(得分:2)

来自wikipedia

  

在数论和组合学中,正整数n的分区,也称为整数分区,是一种将n写为正整数之和的方法。

对于阵列转换,请尝试:

julia> x = collect(partitions(5,3))
2-element Array{Any,1}:
 [3,1,1]
 [2,2,1]

julia> x = partitions(5,3)
Base.FixedPartitions(5,3)

然后

julia> hcat(x...)
3x2 Array{Int64,2}:
 3  2
 1  2
 1  1

答案 1 :(得分:2)

使用Combinatorics.jl库,这是我认为更简单的问题的另一种方法:

multisets(n, k) = map(A -> [sum(A .== i) for i in 1:n],
                      with_replacement_combinations(1:n, k))

这会分配一堆内存,但我认为您当前的方法也是如此。也许制作一流的版本并将其添加到Combinatorics.jl会很有用。

示例:

julia> multisets(2, 1)
2-element Array{Array{Int64,1},1}:
 [1,0]
 [0,1]

julia> multisets(3, 5)
21-element Array{Array{Int64,1},1}:
 [5,0,0]
 [4,1,0]
 [4,0,1]
 [3,2,0]
 [3,1,1]
 [3,0,2]
 [2,3,0]
 [2,2,1]
 [2,1,2]
 [2,0,3]
 ⋮      
 [1,2,2]
 [1,1,3]
 [1,0,4]
 [0,5,0]
 [0,4,1]
 [0,3,2]
 [0,2,3]
 [0,1,4]
 [0,0,5]

参数顺序是从你的后退以匹配数学约定。如果您更喜欢其他方式,那么很容易改变。

答案 2 :(得分:2)

使用词典预表生成算法可以实现一个强大的解决方案,原来 By Donald Knuth 加上经典partitions(n)
这是词典预测生成器:

function lpremutations{T}(a::T)
  b=Vector{T}()
  sort!(a)
  n=length(a)
  while(true)
    push!(b,copy(a))    
    j=n-1
    while(a[j]>=a[j+1])
      j-=1
      j==0 && return(b)
    end
    l=n
    while(a[j]>=a[l])
      l-=1
    end
    tmp=a[l]
    a[l]=a[j]
    a[j]=tmp
    k=j+1
    l=n
    while(k<l)
      tmp=a[k]
      a[k]=a[l]
      a[l]=tmp
      k+=1
      l-=1
    end
  end
end

上述算法将生成所有可能的唯一 具有重复的数组元素的组合:

julia> lpremutations([2,2,0])
3-element Array{Array{Int64,1},1}:
 [0,2,2]
 [2,0,2]
 [2,2,0]

然后我们将生成所有使用partitions(n)求和为n的整数数组(忘记所需数组的长度 m ),并将它们调整为长度 m 使用resize_!

function resize_!(x,m)
  [x;zeros(Int,m-length(x))]
end

主要功能如下:

function lpartitions(n,m)
  result=[]
  for i in partitions(n)
    append!(result,lpremutations(resize_!(i, m)))
  end
  result
end 

检查

julia> lpartitions(3,4)
20-element Array{Any,1}:
 [0,0,0,3]
 [0,0,3,0]
 [0,3,0,0]
 [3,0,0,0]
 [0,0,1,2]
 [0,0,2,1]
 [0,1,0,2]
 [0,1,2,0]
 [0,2,0,1]
 [0,2,1,0]
 [1,0,0,2]
 [1,0,2,0]
 [1,2,0,0]
 [2,0,0,1]
 [2,0,1,0]
 [2,1,0,0]
 [0,1,1,1]
 [1,0,1,1]
 [1,1,0,1]
 [1,1,1,0]

答案 3 :(得分:1)

来自http://www.mathworks.com/matlabcentral/fileexchange/28340-nsumk的MATLAB脚本实际上就像我需要的那样,并且我可以通过给出的描述来执行partition()。朱莉娅版本是

# k - sum, n - number of non-negative integers
function nsumk(k,n)
  m = binomial(k+n-1,n-1);
  d1 = zeros(Int16,m,1);
  d2 = collect(combinations(collect((1:(k+n-1))),n-1));
  d2 = convert(Array{Int16,2},hcat(d2...)');
  d3 = ones(Int16,m,1)*(k+n);
  dividers = [d1 d2 d3];
  return diff(dividers,2)-1;
end

julia> nsumk(3,2)
4x2 Array{Int16,2}:
 0  3
 1  2
 2  1
 3  0

使用daycaster的可爱hcat(x ...)tidbit :) 我仍然希望有一种更紧凑的方式来做到这一点。

第一次提到这种方法似乎是https://au.mathworks.com/matlabcentral/newsreader/view_thread/52610,据我所知,它基于“星星和酒吧”方法https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)