我正在与Project Euler problem 23: Non-abundant sums进行斗争。
我有一个计算大量数字的脚本:
function getSummOfDivisors( $number )
{
$divisors = array ();
for( $i = 1; $i < $number; $i ++ ) {
if ( $number % $i == 0 ) {
$divisors[] = $i;
}
}
return array_sum( $divisors );
}
$limit = 28123;
//$limit = 1000;
$matches = array();
$k = 0;
while( $k <= ( $limit/2 ) ) {
if ( $k < getSummOfDivisors( $k ) ) {
$matches[] = $k;
}
$k++;
}
echo '<pre>'; print_r( $matches );
我已经在互联网上查看了这些数字,这些数字是正确的。我可以将它们乘以2得到数字,这是两个数字的总和。
但是因为我需要找到所有无法编写的数字,所以我只需要反转if
这样的语句:
if ( $k >= getSummOfDivisors( $k ) )
现在应该存储所有,不能创建为丰富数字的总和,但有些东西不会在此处退出。当我总结它时,我会得到一个与正确答案不相符的数字。
我不想看到答案,但我需要一些关于我做错了什么的指导/提示(或者我错过了什么或错过了解)。
编辑:我也尝试了相反的顺序,这意味着,从顶部开始,除以2并检查它们是否丰富。仍然出错了。
答案 0 :(得分:3)
你的逻辑错误在于:
“我可以将它们乘以2并得到两个数字之和的数字”
首先确定所有大量数字[n1,n2,n3 ....]低于分析证明的极限。然后说明所有整数[2 * n1,2 * n2,....]是两个有限数的总和但是 n1 + n2,而n2 + n3也是总和有两个数字。这就是你的错误。你必须计算所有可能的整数,它们是[n1,n2,n3 ....]中任意两个数字的总和,然后用反函数来找到不是的整数。
答案 1 :(得分:3)
我已经在互联网上查看了这些数字,这些数字是正确的。我可以将它们乘以2得到数字,这是两个数字的总和。
不,那不对。只有一个数字<= 16
,但可以写为数字总和的数字<= 32
为24(= 12 + 12),30(= 12 + 18),32(= 12 + 20)。
如果您有k
个号码,则有k*(k+1)/2
个方法可以选择两个(不一定是不同的)。通常,这些对中的很多都会有相同的总和,所以通常只有k*(k+1)/2
个数字可以写成两个给定的k
数字的总和,但通常,那里超过2*k
。
此外,有许多数字<= 28123
只能用大于28123/2
的两个数字中的一个来表示为数字的总和。
现在应该存储所有不能创建为丰富数字的总和的
不,那将存储非丰富数字,那些可能是也可能不是丰富数字的总和,例如32是一个不足的数字(除了32之外的所有除数的总和是31),但可以写成两个数字的总和(见上文)。
你需要找到丰富的数字,但不仅要找到给定限制的一半,你需要检查哪些数字可以写成两个数字的总和。您可以通过获取所有两个数字对(<= $limit
)并标记总和,或者通过检查$number - $abundant
直到您找到一对数字丰富或确定没有总和为{{1 }}
有一些数论可以大大加快它的速度。
答案 2 :(得分:1)
下面是php代码需要320秒
<?php
set_time_limit(0);
ini_set('memory_limit', '2G');
$time_start = microtime(true);
$abundantNumbers = array();
$sumOfTwoAbundantNumbers = array();
$totalNumbers = array();
$limit = 28123;
for ($i = 12; $i <= $limit; $i++) {
if ($i >= 24) {
$totalNumbers[] = $i;
}
if (isAbundant($i)) {
$abundantNumbers[] = $i;
}
}
$countOfAbundantNumbers = count($abundantNumbers);
for ($j = 0; $j < $countOfAbundantNumbers; $j++) {
if (($j * 2) > $limit)
break; //if sum of two abundant exceeds limit ignore that
for ($k = $j; $k < $countOfAbundantNumbers; $k++) { //set $k = $j to avoid duble addtion like 1+2, 2+1
$l = $abundantNumbers[$j] + $abundantNumbers[$k];
$sumOfTwoAbundantNumbers[] = $l;
}
}
$numbers = array_diff($totalNumbers, $sumOfTwoAbundantNumbers);
echo '<pre>';print_r(array_sum($numbers));
$time_end = microtime(true);
$execution_time = ($time_end - $time_start);
//execution time of the script
echo '<br /><b>Total Execution Time:</b> ' . $execution_time . 'seconds';
exit;
function isAbundant($n) {
if ($n % 12 == 0 || $n % 945 == 0) { //first even and odd abundant number. a multiple of abundant number is also abundant
return true;
}
$k = round(sqrt($n));
$sum = 1;
if ($n >= 1 && $n <= 28123) {
for ($i = 2; $i <= $k; $i++) {
if ($n % $i == 0)
$sum+= $i + ( $n / $i);
if ($n / $i == $i) {
$sum = $sum - $i;
}
}
}
return $sum > $n;
}