项目欧拉问题12 - C ++

时间:2010-09-27 21:44:31

标签: c++

关于第一个有500个除数的三角形数,我正在研究问题12。我试图暴力破解解决方案。我在大约35秒内获得300个除数,并且在10分钟内无法获得400。我将改变我的解决方案以使用素因子方法,但我现在已经看到人们仍在不到一分钟内蛮力地获得这个解决方案。

请你批评一下我的代码并告诉我,如果我遗漏的东西会导致这种效率非常低效吗?

unsigned long long TriangleNumberDivisors(int divisorTarget)
{
     unsigned long long triangleNum=1;
         unsigned long long currentNum=2;
     int numOfDivisors=0;


     numOfDivisors=NumOfDivisors(triangleNum);
     while(numOfDivisors<divisorTarget)
     {
         triangleNum+=currentNum;
         currentNum++;
         numOfDivisors=NumOfDivisors(triangleNum);
     }

     return triangleNum;
}

 int NumOfDivisors(unsigned long long dividend)
{
    int numDivisors=0;
    set<unsigned long long> divisors;
    set<unsigned long long>::iterator it;

    for(unsigned long long index=1; index<=dividend/2; index++)
    {
        if(dividend%index==0)
        {
            divisors.insert(index);
            numDivisors++;
            it=divisors.find(dividend/index);
            if(it==divisors.end())
            {
                divisors.insert(dividend/index);
                numDivisors++;
            }
              /*for some reason not checking for dups above and 
just checking for how many items are in the set at the end is slower
             for(it=divisors.begin();it!=divisors.end();it++)
             {
                   numDivisors++;
             }
                  */
        }
    }

    return numDivisors;
}

int main()
{
    cout<<TriangleNumberDivisors(500)<<endl;

    return 0;
}

更新:现在知道了,谢谢。改为只检查数字的平方根,并做了一个额外的检查,看看它是否是一个完美的正方形。这允许我完全删除该组。 500秒的分数在12秒内完成。

4 个答案:

答案 0 :(得分:10)

您目前检查最高dividend/2的除数。您可以将其减少到sqrt(dividend),这是渐近更快的。如果dividend是正方形,则可能需要特殊情况。

问题12的我的C ++代码(它与你的基本相同,但是使用这个下限,并且只计算除数而不是将它们存储在集合中)需要大约1秒

答案 1 :(得分:4)

for(unsigned long long index=1; index<=dividend/2; index++)

我发现您已尝试通过将循环限制为dividend/2来优化此操作,而不是一直迭代到dividend。将自己限制在sqrt(dividend)会更好(从你检查更少的除数的意义上来说)。

另外,如果你用被除数的平方根限制自己,你不必检查重复的除数。这只会发生在正方形数字上,所以只需检查index == dividend / index,以避免重复插入。

答案 2 :(得分:2)

我不确定为什么在NumOfDivisors方法中需要divisorsset类型变量。为什么计算numDivisors(索引高达sqrt( dividend ))是不够的? (set是作为一个平衡的二叉搜索树实现的,它正在减慢方法的速度。)。此外,您似乎正在调用divisors.insert( .. ) 两次

答案 3 :(得分:1)

如果您在进行特定数字时缓存了除数的数量,似乎可以获得一些性能。