项目欧拉#23:非丰富的总和

时间:2013-01-14 15:41:18

标签: php algorithm

我正在与Project Euler problem 23: Non-abundant sums进行斗争。

enter image description here

我有一个计算大量数字的脚本:

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并检查它们是否丰富。仍然出错了。

3 个答案:

答案 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;
}