项目欧拉#23

时间:2016-04-06 15:06:05

标签: c# algorithm oop

我目前正在尝试解决项目euler问题编号23:

  

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

     

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

     

由于12是最小的有限数,1 + 2 + 3 + 4 + 6 = 16,可以写成两个有限数之和的最小数是24.通过数学分析,可以看出所有大于28123的整数可以写成两个数字的总和。然而,即使知道不能表示为两个丰富数字之和的最大数量小于该限制,也不能通过分析进一步降低该上限。

     

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

但是我的代码没有给出正确的结果,而它似乎完全正常。我计算的数字超过了足够数量吗?

private static void Main()
    {
        List<int> AbudantNumbers = new List<int>();
        long sum = 0;
        for (int i = 12; i <= 28123; i++)
        {
            int abudantNumber = GetProperDivisor(i);
            if (abudantNumber > i)
            {
                AbudantNumbers.Add(i);
            }
        }

        for (int k = 1; k <= 28123; k++)
        {
            int count = 0;
            for (int i = 0; i < AbudantNumbers.Count; i++)
            {
                count = 0;
                if (AbudantNumbers[i] > k)
                {
                    break;
                }
                for (int j = i; j < AbudantNumbers.Count; j++)
                {
                    if (AbudantNumbers[j] > k)
                    {
                        break;
                    }
                    if (AbudantNumbers[i] + AbudantNumbers[j] == k)
                    {
                        count++;
                        break;
                    }
                }
            }
            if (count == 0)
            {
                sum += k;
            }
        }
        Console.WriteLine(sum);
        Console.ReadKey();
    }

    private static int GetProperDivisor(int input)
    {
        int sum = 1;
        for (int i = 2; i <= input / 2; i++)
        {
            if (input%i == 0)
            {
                sum += i;
            }
        }
        return sum;
    }

我的结果是:297632990 正确的结果是:4179871

当我的代码中没有明显错误时,差异很大。

我的第二种方法:

        for (int k = 1; k <= 28123; k++)
        {
            var k1 = k;
            int count =
                (from t1 in AbudantNumbers.TakeWhile(t1 => t1 <= k1) let a = t1 select t1).Count(
                    t1 => AbudantNumbers.TakeWhile(t => t <= k).Any(t => t1 + t == k));
            if (count == 0)
            {
                sum += k;
            }
        }

我的想法是得到所有数量小于28123的数字,而不是检查小于28123的所有整数(上面的所有内容都有2个数字的总和),而不是旋转所有数字,最后检查abundantNumber1 + abundantNumber2 == currentNumber是否{{1}}所以我们打破了循环,因为我们只需要那些没有2个丰富数字的总和。

1 个答案:

答案 0 :(得分:0)

当您发现当前数字k是两个数字a[i] + a[j]的总和时,您设置count然后突破循环 - 从内循环中取出j,即。{/ p>

这意味着您仍然会考虑所有剩余的i,并为其重置count。实际上,您只考虑小于或等于k的最后一个数字。这两个数字的总和不太可能涉及这个数字,因此在大多数情况下,添加数字count == 0的条件是错误的。

当你发现k == a[i] + a[j]时,你必须打破两个最内层的循环。 C#似乎没有标记循环,因此最好将内循环重构为一个函数,该函数将大量数字列表和k作为参数;然后,您可以在满足条件时返回true

作为快速但难看的修复,您可以添加

if (count) break;
循环过j之后

但是,你的方法非常无效。最好只在所有大量数字上编写两个嵌套循环,然后在它们小于28124时将它们的总和添加到一个集合中。然后添加1到28124之间不在集合中的所有数字。