如何解决找到最多 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^m
将 sum
乘以 (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 举报,一经查实,本站将立刻删除。