簡體   English   中英

如何加快可和數字算法?

[英]How do I speed up my Amicable number algorithm?

完成100,000(n)個限制需要很長時間。

我懷疑問題出在CalculateAmicable()上 ,該數字越來越大並且需要花費更多的時間進行計算。 我可以做些什么來使其加快速度呢?

public static void Main (string[] args)
    {
        CheckAmicable (1, 100000);

    }

    public static int CheckAmicable(int start, int end)
    {
        for (int i = start; i < end; i++) {

            int main = CalculateAmicable (i); //220
            int temp = CalculateAmicable (main); //284
            int compare = CalculateAmicable (temp); //220
            if (compare == main) {
                if (main != temp && temp == i) {
                    Console.WriteLine (main + " = " + temp + " = " + compare + " i: " + i);
                    i = compare + 1;
                }
            }
        }
        return 0;
    }

    public static int CalculateAmicable(int number)
    {
        int total = 0;
        for (int i = 1; i < number; i++) {
            if (number%i == 0){
                total += i;
            }
        }
        return total;
    }

注意:英語不是我的母語!

是的, CalculateAmicable 效率低下 O(N)復雜度-因此您需要進行N測試1e5 * 1e5 == 1e10 百億次運算很慢。 將復雜度降低到O(log(N))

  int n = 100000;

  //TODO: implement IList<int> GetPrimesUpTo(int) yourself
  var primes = GetPrimesUpTo((int)(Math.Sqrt(n + 1) + 1));

  // Key - number itself, Value - divisors' sum 
  var direct = Enumerable
    .Range(1, n)
    .AsParallel()
    .ToDictionary(index => index, 
                  index => GetDivisorsSum(index, primes) - index);

  var result = Enumerable
    .Range(1, n)
    .Where(x => x < direct[x] && 
                direct.ContainsKey((int) direct[x]) &&
                direct[(int) direct[x]] == x)
    .Select(x => $"{x,5}, {direct[x],5}");

  Console.Write(string.Join(Environment.NewLine, result));

結果不到一秒鍾(Core i7 3.2Ghz .Net 4.6 IA-64):

  220,   284
 1184,  1210
 2620,  2924
 5020,  5564
 6232,  6368
10744, 10856
12285, 14595
17296, 18416
63020, 76084
66928, 66992
67095, 71145
69615, 87633
79750, 88730

詳細信息GetDivisorsSum

private static long GetDivisorsSum(long value, IList<int> primes) {
  HashSet<long> hs = new HashSet<long>();

  IList<long> divisors = GetPrimeDivisors(value, primes);

  ulong n = (ulong) 1;
  n = n << divisors.Count;

  long result = 1;

  for (ulong i = 1; i < n; ++i) {
    ulong v = i;
    long p = 1;

    for (int j = 0; j < divisors.Count; ++j) {
      if ((v % 2) != 0)
        p *= divisors[j];

      v = v / 2;
    }

    if (hs.Contains(p))
      continue;

    result += p;

    hs.Add(p);
  }

  return result;
}

GetPrimeDivisors

private static IList<long> GetPrimeDivisors(long value, IList<int> primes) {
  List<long> results = new List<long>();

  int v = 0;
  long threshould = (long) (Math.Sqrt(value) + 1);

  for (int i = 0; i < primes.Count; ++i) {
    v = primes[i];

    if (v > threshould)
      break;

    if ((value % v) != 0)
      continue;

    while ((value % v) == 0) {
      value = value / v;

      results.Add(v);
    }

    threshould = (long) (Math.Sqrt(value) + 1);
  }

  if (value > 1)
    results.Add(value);

  return results;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM