【问题标题】:Finding perfect numbers (optimization)寻找完美数字(优化)
【发布时间】:2011-02-08 17:50:30
【问题描述】:

作为编程挑战的一部分,我用 C# 编写了一个程序来查找一定范围内的完美数字。但是,我意识到计算超过 10000 的完美数字时非常慢。是否有任何优化方法可以找到完美数字?我的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleTest
{
 class Program
 {
  public static List<int> FindDivisors(int inputNo)
  {
   List<int> Divisors = new List<int>();
   for (int i = 1; i<inputNo; i++)
   {
    if (inputNo%i==0)
     Divisors.Add(i);
   }
   return Divisors;
  }

  public static void Main(string[] args)
  { 
   const int limit = 100000;

   List<int> PerfectNumbers = new List<int>();
   List<int> Divisors=new List<int>();
   for (int i=1; i<limit; i++)
   {
    Divisors = FindDivisors(i);
    if (i==Divisors.Sum())
     PerfectNumbers.Add(i);
   }

   Console.Write("Output =");

   for (int i=0; i<PerfectNumbers.Count; i++)
   {
    Console.Write(" {0} ",PerfectNumbers[i]);
   }

   Console.Write("\n\n\nPress any key to continue . . . ");
   Console.ReadKey(true);
  }
 }
} 

【问题讨论】:

  • 计算完美数就像计算每周有多少天。结果永远不会改变,所以不要计算它们。查找它们。
  • @ Daniel Dyson - 发帖者表示这是某种编程挑战,我怀疑他会对一系列预先计算的答案感到满意 =)
  • @ paradox - 你还有另一个问题,因为完美数是如此稀疏,如果你的程序认真搜索完美数,你很快就会打破你的 int 限制。
  • @乔尔·古德温。这是一个公平的观点,但如果我向我的团队中的一个人提出这样的挑战,我希望他们能给出答案,即这些应该被存储而不是计算。毕竟,按照我的阅读方式,挑战是“找到完美的数字”,而不一定是“计算”它们。如果它们都已经在那个范围内计算过了,为什么还要再计算呢?编程就是想出最好的解决方案。这并不总是一种算法。
  • @Daniel Dyson。如果我在现实世界的问题中需要它们,肯定会存储解决方案 - 但对我来说,这个问题的精神是“你如何优化这个算法?”然而,寻找它是一件令人讨厌的事情,因为它们分布得如此之薄,即使与素数相比也是如此。

标签: c# optimization number-theory perfect-numbers


【解决方案1】:

完美数会改变吗?编号Look here。当然,它们应该计算一次然后存储。 在您的情况下,唯一的结果将是

6
28
496
8128

下一个是 33550336。超出你的范围。

【讨论】:

    【解决方案2】:

    解决此类问题的一种方法是在内存中为每个数字构建一个巨大的数组,然后将数字划掉。

    【讨论】:

      【解决方案3】:

      使用公式

      testPerfect = 2n-1(2n - 1)

      要产生可能性,然后检查这个数字是否真的完美。

      try this for some bedtime reading

      【讨论】:

      • +1,但请注意,这不会找到任何奇数完美数(如果存在这样的数字)。不过,在这种情况下不是问题。
      • @balpha 你是怎么得到上标的?
      • 看看the source&lt;sup&gt;是列入白名单的HTML标签之一,但你必须使用&lt;pre&gt;而不是4空格缩进代码块,因为后者显示HTML标签字面意思
      • 我使用了那个生成公式并检查了数字 % 9 == 1; :) 谢谢!
      • 对于那些对 balpha 的评论感兴趣的人来说,奇完美数的下限为 10**1500。如果这还不够难处理,他们还有一个疯狂的要求清单,他们需要满足,请参阅en.wikipedia.org/wiki/Perfect_number#Odd_perfect_numbers
      【解决方案4】:

      只是我很明显的一点:您不需要检查每个除数。没有必要寻找超过 inputNo/2 的除数。这减少了一半的计算,但这并没有快一个数量级。

      【讨论】:

        【解决方案5】:

        如果您仍在寻找计算完美数字的方法。 这通过前一万很快,但三千三百万的数字有点慢。

        public class Perfect {
        private static Perfect INSTANCE = new Perfect();
        
        public static Perfect getInstance() {
            return INSTANCE;
        }
        
        /**
         * the method that determines if a number is perfect;
         * 
         * @param n
         * @return
         */
        public boolean isPerfect(long n) {
            long i = 0;
            long value = 0;
            while(++i<n){
                value = (0 == n%i?value+i:value);
            }
            return n==value;
        }
        }
        

        【讨论】:

          【解决方案6】:

          对于任何对基于 LINQ 的方法感兴趣的人,在确定调用者提供的整数值是否是完美数字时,以下方法对我来说非常有效且有效。

          bool IsPerfectNumber(int value)
          {
              var isPerfect = false;
          
              int maxCheck = Convert.ToInt32(Math.Sqrt(value));
              int[] possibleDivisors = Enumerable.Range(1, maxCheck).ToArray();
              int[] properDivisors = possibleDivisors.Where(d => (value % d == 0)).Select(d => d).ToArray();
              int divisorsSum = properDivisors.Sum();
          
              if (IsPrime(divisorsSum))
              {
                  int lastDivisor = properDivisors.Last();
                  isPerfect = (value == (lastDivisor * divisorsSum));
              }
          
              return isPerfect;
          }
          

          为了简单明了,省略了我在 IsPerfectNumber() 中使用的 IsPrime() 的实现。

          【讨论】:

            【解决方案7】:

            要继续查尔斯·加金特的回答,有一种非常快速的方法可以检查梅森数 a.k.a. 2^n - 1 是否为素数。它被称为Lucas-Lehmer test 基本的伪代码(取自维基百科页面)是:

            // Determine if Mp = 2p − 1 is prime for p > 2
            Lucas–Lehmer(p)
                var s = 4
                var M = 2p − 1
                repeat p − 2 times:
                    s = ((s × s) − 2) mod M
                if s == 0 return PRIME else return COMPOSITE
            

            【讨论】:

              猜你喜欢
              • 2016-09-26
              • 2022-11-09
              • 1970-01-01
              • 2012-10-01
              • 2020-02-14
              • 2017-03-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多