سؤال

قمت بترميز برنامج في 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);
  }
 }
} 
هل كانت مفيدة؟

المحلول

استخدم الصيغة

testPerfect = 2N-1(2ن - 1)

لتوليد إمكانات ثم تحقق من أن الرقم هو في الواقع مثالي.

جرب هذا لبعض القراءة قبل النوم

نصائح أخرى

هل تتغير الأرقام المثالية؟ رقم. انظر هنا. بالتأكيد ، يجب حسابها مرة واحدة ثم تخزينها. في حالتك ، ستكون النتائج الوحيدة

6
28
496
8128

التالي هو 33550336. خارج نطاقك.

مجرد واحد واضح مني: لا تحتاج إلى التحقق من كل مقسوم. لا جدوى من البحث عن المقسومات في الماضي inputNo/2. وهذا يقلل من نصف الحسابات ، لكن هذا ليس ترتيبًا أسرع.

تتضمن إحدى الطرق لحل أشياء مثل هذه بناء صفيف ضخم في ذكرى كل رقم ، ثم عبور الأرقام.

إذا كنت لا تزال تبحث عن شيء لحساب أرقام مثالية. هذا يمر عبر عشرة آلاف سريع للغاية ، لكن عدد 33 مليون أبطأ قليلاً.

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;
}
}

لأي شخص مهتم بنهج قائم على 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;
}

من أجل البساطة والوضوح ، تم حذف تنفيذي لـ ISPrime () ، والذي يتم استخدامه داخل ISPerfectNumber ().

للمتابعة من إجابة Charles Gargent ، هناك طريقة سريعة جدًا للتحقق مما إذا كان رقم Mersenne AKA 2^n - 1 هو Prime. يطلق عليه اختبار لوكاس ليمرالرمز الكاذب الأساسي على الرغم من (مأخوذة من صفحة ويكيبيديا) هو:

// 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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top