欧拉23号项目C++

Project Euler 23 C++

本文关键字:C++ 项目 23号 欧拉      更新时间:2023-10-16

我一直在研究欧拉#23项目。

这是任务:

问题 23

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

如果一个数的适当除数之和小于 n,则称为不足,如果该和超过 n,则称为丰度。

由于 12 是最小的丰度数,1 + 2 + 3 + 4 + 6 = 16,因此可以写为两个丰度数之和的最小数是 24。通过数学分析可以证明,所有大于28123的整数都可以写成两个丰度数之和。然而,这个上限不能通过分析进一步降低>即使已知不能表示为两个丰度之和的最大数小于这个极限。

找到所有正整数的总和,这些正整数不能写成两个丰数字的总和。

#include<iostream>
using namespace std;
int main() {
long long sum;
int numbers[30000];
int ab[7000];
for(int i=0;i<7000;i++)
ab[i]=0;
//array of numbers
for(int i=0; i<28123;i++)
numbers[i]=i+1;
//abundant numbers
int abud_counter=0;
for(int i=1; i<28124;i++){
//factors
int temp=0;
for(int j=2;j<=i/2;j++) {
if(i%j==0)
temp=temp+j;
}
temp=temp+1;
if(temp > i) {
ab[abud_counter]=i;
numbers[i-1]=0;
abud_counter=abud_counter+1;
if(abud_counter>6965)
break;
}
}
//all shit
int array2[7000];
for(int i=0; i<6965; i++)
array2[i]=ab[i];
int k=0;
for(int i=0;i<6965;i++) {
for(int j=0;j<6965;j++) {
if(ab[i]+array2[j]==numbers[ab[i]+array2[j]-1]) {
numbers[ab[i]+array2[j]-1]=0;
}
}
}
sum=0;
for(int i=0; i<28123; i++) {
sum = sum+numbers[i]; 
}
cout<<sum;
return 0;
}

我得到的总价值是4178876。正确答案是 4179871.我花了 10 个小时查看我的代码,但找不到错误。我应该更改什么来更正错误?我的答案很接近。提前致谢

附言。我是学习新手。运行时间为 1.3 秒,任何优化也将很有用。

发布的代码中存在一些问题,除了一些低效率和滥用幻数。

当填充丰数组时,number数组的某些元素被错误地归零。

if(temp > i) {
ab[abud_counter]=i;
numbers[i-1]=0;               // <----- Why? Remove this line.
abud_counter=abud_counter+1;
if(abud_counter>6965)
break;
}

当我尝试这个程序时,由于这一行,我得到了一个分段错误

for(int i=0;i<6965;i++) {
for(int j=0;j<6965;j++) {
if(ab[i]+array2[j]==numbers[ab[i]+array2[j]-1]) {
//                      ^^^^^^^^^^^^^^^^^^   
numbers[ab[i]+array2[j]-1]=0;
}
}
}

numbers有 30000 个元素,但ab[i]array2[j]的值最多可以达到 28123。

顺便说一句,array2是多余的,它只是ab的副本.

生成正确 4179871 值的算法的修改版本可能如下所示

#include <array>
#include <iostream>
#include <vector>
long sum_of_dividends(int n)
{
long sum{1};
int i = 2;
for (int j = n; i < j; ++i)
{
if ( n % i == 0 )
{
sum += i;
j = n / i;
if (i == j)
break;
sum += j;
}
}
return sum;
}
int main() 
{
std::vector<int> abundants;
abundants.reserve(7000);
constexpr int max_value = 28123;
for (int i{1}; i <= max_value; ++i)
{
if (sum_of_dividends(i) > i)
abundants.push_back(i);
}
std::array<bool, max_value> are_sums{};
for (unsigned i{}; i < abundants.size(); ++i)
{
for (unsigned j{i}; ; ++j)
{
long k = abundants[i] + abundants[j];
if (k >= max_value)
break;
are_sums[k] = true;
} 
}
long sum{};
for (int i{}; i < max_value; ++i)
if (!are_sums[i])
sum += i;
std::cout << sum << 'n';
}

虽然前面的实现利用了更快的方法来计算数字的股息之和,但处理时间的大幅改进需要一种不同的方法来搜索丰富的数字。

以下片段利用了一个类似于埃拉托色尼筛子的想法,而不是搜索范围内每个数字的股息,它只是对适当数字的每个股息求和。

std::vector<int> abundants;
std::vector<long> dividends_sums(max_value + 1, 1);
for (int i{2}; i <= max_value; ++i)
{
for (int j{i * 2}; j <= max_value; j += i)
dividends_sums[j] += i;
if (dividends_sums[i] > i)
abundants.push_back(i);
}

可以在此处看到此修改的影响。