微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

找到最多 100 万个“相当不错”的数字的最佳方法?

如何解决找到最多 100 万个“相当不错”的数字的最佳方法?

我正在处理一项涉及“相当不错”的数字的作业。该任务将它们描述为:

一个“相当不错”的数字是一个整数,它的“坏度”——它的除数之和与数字本身之差的大小——不大于一个指定的值。例如,如果最大坏度是设置为 3,有 12 个“相当不错”的数字小于 100:2、3、4、6、8、10、16、18、20、28、32 和 64;你的任务是编写一个 C++ 程序,非常好,它确定小于指定值的指定最大 badness 的数量。在执行程序时,将限制值和最大 badness 指定为命令行参数。”

该任务要求我编写一个程序,该程序可以打印具有高达一百万的指定坏度限制的完美数字。所以,相当好的 1000000 的命令行参数 1 应该打印 2 4 6 8 16 28 32 64 128 256 496 512 1024 2048 4096 8128 8192 16384 32768 65536 131072 262144 524288

我已经得到了这个与以下代码一起工作

#include <iostream>

using namespace std;

int main(int argc,char *argv[]) {

    const int limit = argc > 1 ? atoi(argv[1]) : 1000000;
    const int badness = argc > 2 ? atoi(argv[2]) : 10;

    for(int number = 2; number < limit; number++) {
        int sum = 1;
        for (int factor = 2; factor < number; factor++){
            if (number % factor == 0) {
                sum += factor;
            }
        }

        if (number >= (sum - badness) && number <= (sum + badness)) {
            cout << number << " ";
        }
    }

    return 0;
}

唯一的问题是,这段代码在找到高达 100 万的“相当不错”的数字时太慢了。有没有办法优化这个?

谢谢

解决方法

如果 f 是 n 的因数,那么 n/f 也是如此(尽管当 f 是 n 的平方根时,f 和 n/f 是相同的因数)。因此,您可以通过仅将因子计数到 sqrt(number) 来使代码更快,然后当您找到一个时还包括匹配的因子数/因子(平方根情况除外)。

for (int factor = 2; factor * factor <= number; factor++){
    if (number % factor == 0) {
        sum += factor;
        if (factor * factor != number) {
            sum += number / factor;
        }
    }
}

此代码在我的机器上运行时间为 1.554 秒,limit 为 100 万,badness 为 1。等待原始代码完成几分钟后,我感到很无聊。

为了使代码更快,您可以找到数字的质因数分解,并使用 formula for the sum of the divisors based on the prime factorization

即使没有预先计算素数,使用这种方法在我的机器上运行时间为 0.713 秒。这是我从 sum 计算 number 的代码:

int n = number;
int i = 2;
while (n > 1) {
    if (i * i > n) {
        sum *= (n + 1);
        break;
    }
    int pp = i;
    while (n % i == 0) {
        pp *= i;
        n /= i;
    }
    sum *= (pp - 1) / (i - 1);
    i += 1;
}
sum -= number;

它找到所有除 number 的素数幂,并且对于每个 p^msum 乘以 (p^(m+1) - 1) / (p - 1)。与第一个解决方案一样,它在 i*i > n 时提前停止,这意味着 n 是素数。

在一般情况下,它比第一个解决方案快得多,因为尽管我们仍在进行试除,但随着找到质因子,n 会变小。

如果您预先计算了一个足够大的素数列表(也就是说,它至少包含一个大于 limit 的平方根的素数),您在计算 sum 时可以再次高效一点:

int n = number;
for (int i = 0; primes[i] * primes[i] <= n; ++i) {
    int pp = primes[i];
    while (n % primes[i] == 0) {
        pp *= primes[i];
        n /= primes[i];
    }
    sum *= (pp - 1) / (primes[i] - 1);
}
if (n > 1) sum *= (n + 1);
sum -= number;

以这种方式计算 sum 的代码在我的机器上运行时间为 0.189 秒。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。