使用嵌套循环的分布

时间:2015-01-16 22:15:10

标签: ruby

我想编写一个程序,为给定的n生成所有发行版。

例如,如果我输入n等于7,则返回的结果为:

7 
6 1
5 2
5 1 1
4 3
4 2 1
4 1 1 1
3 3 1
3 2 2
3 2 1 1
3 1 1 1 1
2 2 2 1
2 2 1 1 1
2 1 1 1 1 1
1 1 1 1 1 1 1

我写了以下代码:

def sum(a, n)
  for i in 1..a.length
    a.each do |a|
      z = a+i
      if z == n
        print i
        puts a
      end
    end
  end
end

def distribution(n)
  numbers_container = []
  for i in 1..n-1
    numbers_container<<i  
  end
  sum(numbers_container,n)
end

puts "Enter n"
n = gets.chomp.to_i
distribution(n)

我被困在程序需要检查超过两个augends的总和的部分。我不知道如何编写第二个循环。

3 个答案:

答案 0 :(得分:2)

我建议你使用递归。

<强>代码

def all_the_sums(n, mx=n, p=[])
  return [p] if n.zero?
  mx.downto(1).each_with_object([]) { |i,a|
    a.concat(all_the_sums(n-i, [n-i,i].min, p + [i])) }
end

示例

all_the_sums(7)
  #=> [[7],
  #    [6, 1],
  #    [5, 2], [5, 1, 1],
  #    [4, 3], [4, 2, 1], [4, 1, 1, 1],
  #    [3, 3, 1], [3, 2, 2], [3, 2, 1, 1], [3, 1, 1, 1, 1],
  #    [2, 2, 2, 1], [2, 2, 1, 1, 1], [2, 1, 1, 1, 1, 1],
  #    [1, 1, 1, 1, 1, 1, 1]] 

<强>解释

论证mx是为了避免产生结果。例如,一个序列是[4,2,1]。这个数组的元素有六种排列(例如[4,1,2][2,4,1]等等),但我们只想要一个。

现在考虑通过以下方式执行的计算:

all_the_sums(3)

下面的每个八维空格缩写反映了对该方法的递归调用。

我们从

开始
n = 3
mx = 3
p = []

return [[]] if 3.zero? #=> no return
# first value passed block by 3.downto(1)..
i = 3
a = []
# invoke all_the_sums(0, [0,3].min, []+[3]) 

        all_the_sums(0, 0, [3])
        return [[3]] if 0.zero? #=> return [[3]]

a.concat([[3]]) #=> [].concat([[3]]) => [[3]]
# second value passed block by 3.downto(1)..
i = 2
a = [[3]]
# invoke all_the_sums(1, [1,2].min, []+[2])  

        all_the_sums(1, 1, [2])
        return [[2]] if 1.zero? #=> do not return
        # first and only value passed block by 1.downto(1)..
        i = 1
        a = []
        # invoke all_the_sums(0, [0,1].min, [2]+[1])  

                all_the_sums(0, 0, [2,1])
                return [[2,1]] if 0.zero? #=> [[2,1]] returned

        a.concat([[2,1]]) #=> [].concat([[2,1]]) => [[2,1]]
        return a #=> [[2,1]] 

a.concat([[2,1]]) #=> [[3]].concat([[2,1]]) => [[3],[2,1]]
# third and last value passed block by 3.downto(1)..
i = 1
a = [[3],[2,1]]
# invoke all_the_sums(2, [2,1].min, [1])  

         all_the_sums(2, 1, [1])
         return [] if 2.zero? #=> [] not returned
         # first and only value passed block by 1.downto(1)..
         i = 1
         a = []
         # invoke all_the_sums(1, [1,1].min, [1]+[1])  

                 all_the_sums(1, 1, [1,1])
                 return [1,1] if 1.zero? #=> [1,1] not returned
                 # first and only value passed block by 1.downto(1)..
                 i = 1
                 a = []
                 # invoke all_the_sums(0, [0,1].min, [1,1]+[1]])  

                         all_the_sums(0, 0, [1,1,1])
                         return [1,1,1] if 1.zero?
                           #=> return [1,1,1]

                 a.concat([[1,1,1]]) #=> [[1,1,1]]
                 return a #=> [[1,1,1]] 

         a.concat([[1,1,1]]) #=> [].concat([[1,1,1]]) => [[1,1,1]]
         return a #=> [[1,1,1]] 

a.concat([[1,1,1]]) #=> [[3],[2,1]].concat([[1,1,1]])
return a #=> [[3],[2,1],[1,1,1]]

答案 1 :(得分:0)

您可以使用带有parameters的一元来获得无限量的参数:

def test_method *parameters
  puts parameters
  puts parameters.class
end

test_method("a", "b", "c", "d")

因此,块内的parameters成为参数数组。然后,您可以轻松地遍历它们:

parameters.each { |par| p par }

此外,请勿使用for循环,因为它们的可读性低于使用each方法。

[1..n-1].each do i
   # body omitted
 end

答案 2 :(得分:0)

如果您尝试递归调用sum,我认为您可以解决这个问题。在这之后:

print i
puts a

再次尝试拨打sum,如下所示:

sum((1..a).to_a, a)

它不会解决它,但它可能会引导你朝着正确的方向前进。