需要一种方法来使这段代码运行得更快

时间:2013-12-19 15:05:40

标签: c++ algorithm math

我正在尝试解决Project Euler problem 401。他们唯一能找到解决方法的方法就是蛮力。我已经运行这个代码10分钟没有任何答案。任何人都可以帮助我改进它的想法。

代码:

#include <iostream>
#include <cmath>
#define ull unsigned long long

using namespace std;

ull sigma2(ull n);
ull SIGMA2(ull n);

int main()
{
    ull ans = SIGMA2(1000000000000000) % 1000000000;

    cout << "Answer: " << ans << endl;

    cin.get();
    cin.ignore();

    return 0;
}

ull sigma2(ull n)
{
    ull sum = 0;
    for(ull i = 1; i<=floor(sqrt(n)); i++)
    {
        if(n%i == 0)
        {
            sum += (i*i)+((n/i)*(n/i));
        }
        if(i*i == n)
        {
            sum -= n;
        }
    }
    return sum;
}

ull SIGMA2(ull n)
{
    ull sum = 0;
    for(ull i = 1; i<=n; i++)
    {
        sum+=sigma2(i);
    }
    return sum;
}

5 个答案:

答案 0 :(得分:3)

你错过了一些分隔符,如果a / b = c,ba的分隔符,那么c也会是a的分隔符但是c可能大于floor(sqrt(a)),例如3&gt; (sqrt(6))但是除以6。

然后你应该把你的楼层(sqrt(n))放在一个变量中并使用for中的变量,否则你会重新计算每个非常昂贵的操作。

答案 1 :(得分:2)

您可以做一些简单的优化:

  • 内联sigma2
  • 在循环之前计算floor(sqrt(n))(但编译器可能无论如何都要这样做),
  • 1n预先计算所有整数的平方,然后使用数组查找而不是乘法

通过改变方法,您将获得更多收益。想想你想要做的事情 - 将所有整数的除数从1到n求平方。您将除数除以它们的除法,但您可以在此总和中重新组合术语。让我们按其价值对除数进行分组:

  • 1对所有内容进行划分,以便在总和中显示n次,总计1*1*n
  • 2划分evens并显示n/2(整数除法!)次,总计2*2*(n/2)
  • k ...将带来k*k*(n/k)总计。

因此,我们应该将k*k*(n/k) k1加到n

答案 2 :(得分:1)

您可以执行的一项简单优化是,数字中会有许多重复因素。

所以首先估计一个因子中有多少个数(所有N个数) 在多少个数字中,2是一个因子(N / 2) ...
其他人也一样。

只需将它们的方块与它们的频率相乘。

然后,时间复杂度将直接减少到O(N)

答案 3 :(得分:1)

想想问题。

Bruteforce你尝试的方式显然不是一个好主意。

你应该想出更好的东西...... 是不是有任何方法如何使用一些很好的素数分解方法来加速计算?是不是有任何递归模式?试着找点什么......

答案 4 :(得分:0)

有明显的微优化,例如++ i而不是i ++或者从循环中获取楼层(sqrt(n))(这两个浮点运算与循环中的其他整数运算相比非常昂贵),并且仅使用一次n / i(对其使用虚拟变量,然后计算虚拟的平方)。

算法中也有相当明显的简化。例如,SIGMA2(i)= SIGMA2(i-1)+ sigma2(i)。但是不要使用递归,因为你需要一个非常庞大的数字,这将无法工作,你的堆栈内存将耗尽。使用循环而不是递归。有巨大的改进潜力。

而且,有一个更大的问题 - 10 ^ 15有15位数。这个数字的平方有30位数。没有办法你可以将它存储到unsigned long long中,我认为它有20个数字。所以你需要以某种方式使用模数10 ^ 9(赋值的结束)并为你的计算获得额外的空间......

当使用蛮力时,打印每个数百万个数字的临时结果,例如,让您知道您接近最终结果的速度有多快。盲目等待10分钟并不是一个好主意。