无法找到Project Euler 23的正确编号

时间:2018-08-28 02:32:41

标签: ruby

2个小时以来,我一直在尝试查找问题,正确的答案是4179871,但我一直只收到4177763,

  

一个完美数是一个其适当除数之和的数字   完全等于数字。例如,适当的总和   28的除数是1 + 2 + 4 + 7 + 14 = 28,这意味着28   是一个完美的数字。

     

如果数字n的适当除数之和为   小于n,并且如果总和超过n,则称为丰富。

     

因为12是最小的丰富数,所以1 + 2 + 3 + 4 + 6 = 16,因此   可以写为两个丰富数字之和的最小数字   是24。通过数学分析,可以证明所有整数   大于28123可以写为两个丰富数字的总和。   但是,无法通过分析进一步降低此上限   即使已知最大的数字   表示为两个丰富数字之和小于此限制。

     

查找所有不能写为的正整数之和   两个丰富数字的总和。

def factors(num) # function that returns array of factors
  factorsNums = []
  for i in 1..Math.sqrt(num).ceil
    if num % i == 0
      factorsNums.push(i) if i != num
      factorsNums.push(num / i) if ((num / i) < num) && ((factorsNums.include? (num / i)) == false)
    end
  end
  factorsNums
end
abundantNumbers = []

for i in 1..28123 #This loop will push into the array "abundantNumbers" each number from 1 to 28123 that is an abundant number (a number in which the sum of its divisors is bigger than the number itself)
  abundantNumbers.push(i) if factors(i).inject(0, :+) > i
end

abundantSums = []
#this 2 dimensional loop will find the every possible sum of 2 abundant numbers from which we got in the last for loop and push them into another array "abundantSums"
  for i in 0...abundantNumbers.length
    for j in i...abundantNumbers.length
      sum = abundantNumbers[i] + abundantNumbers[j]
      abundantSums.push(sum) if sum <= 28123
    end
  end


abundantSums = abundantSums.uniq.sort #remove duplicates and sort the array

notSums = []

for i in 1..28123 #find numbers which are not the sum of 2 abundant numbers and push them into the array "notSums"
  notSums.push(i) if (abundantSums.include? i) == false 
end
print notSums.inject(0, :+) #print out sum of array elements that are not sums of abundant numbers

2 个答案:

答案 0 :(得分:2)

问题是如何处理因子,数组中包含因子的重复项,这是解决方法:

def factors(num) # function that returns array of factors  
  factorsNums = []   
  for i in 1..Math.sqrt(num).ceil
    if num % i == 0
      factorsNums.push(i) if i != num && !factorsNums.include? i
      factorsNums.push(num / i) if ((num / i) < num) && ((factorsNums.include? (num / i)) == false)
    end   
  end   
  factorsNums 
end

答案 1 :(得分:1)

在构造一个返回给定正整数的适当因子数组的方法时,我们可以使用方法Prime::prime_division,该方法确定每个正整数的素数分解。例如,

require 'prime'

Prime.prime_division(180)
  #=> [[2, 2], [3, 2], [5, 1]]

这意味着

180 = 2**2 * 3**2 * 5**1

此外,180的每个因子都等于

2**n2 * 3**n3 * 5**n5

其中0 << n2 << 20 << n3 << 20 <= n5 <= 1适当因素是除180之外的所有其他因素

(2+1)*(2+1)*(1+1) - 1 #=> 17

因此,我们可以如下定义OP的方法factors(我将其重命名为proper_factors)。

def proper_factors(n)
  first, *rest = Prime.prime_division(n).
                       map { |m,pow| (0..pow).map { |p| m**p } }
  first.product(*rest).
        map { |arr| arr.reduce(:*) } - [n]
end

proper_factors(180)
  #=> [1, 5, 3, 15, 9, 45, 2, 10, 6, 30, 18, 90, 4, 20, 12, 60, 36]

接下来,创建一个介于12和28123之间的大量数字的数组。

max_val = 28123    
abundants = (12..max_val).select { |n| proper_factors(n).sum > n }
  #=> [12, 18, 20, 24, 30, 36, 40, 42, 48, 54, 56, 60, 66, 70, 72, 78, 80,
  #    ...
  #    12078, 12080, 12084, 12090, 12096, 12100, 12102, 12104, 12108, 12110,
  #    ...
  #    28086, 28092, 28098, 28100, 28104, 28110, 28112, 28116, 28120, 28122]
abundants.size
  #=> 6965

不等于两个整数的和的正数之和等于1和28123之间的数字之和(算术级数之和)减去1和28123之间等于两个之和的数字之和大量的。等于两个丰富数字之和的数字比不具有该属性的数字更容易计算,因此我们将所需的和计算为两个和之和。

1到28123之间的数字总和等于

all_sum = 28123*(1+28123)/2
  #=> 395465626

我们现在计算1到28123之间的数字总和,该数字总和等于两个丰富数字的总和。为此,我们仅累加(按数组)不超过28123的所有成对数字的总和。当然,这将产生许多重复项,因此我们必须uniq对数组求和,然后再对其求和。 (我们可以累积成一个集合。)

half_max = max_val/2
  #=> 14061
last_abundants_idx = abundants.size - 1
  #=> 6964

sum_nbrs_sum_two = abundants.each_with_index.with_object([]) do |(n,i),found|
  break found if n > half_max
  (i..last_abundants_idx).each do |j|
    m = n + abundants[j]
    break if m > max_val
    found << m
  end
end.uniq.sum
  #=> 391285755

这里数组foundfound.uniq分别包含1214881526667元素。 1

最后一步是以下步骤。

all_sum - sum_nbrs_sum_two
  #=> 4179871

1请注意,第三行包含范围(i..last_abundants_idx),而不是(i+1..last_abundants_idx),以包括数字2*abundants[i]。对于所有i都是如此,但是对于大多数i2*abundants[i]等于两个不同的丰富数之和。实际上,如果将i..更改为i+1..,总和(391285755)仅减少64