Найдите первое треугольное число, имеющее 50 делителей?

-----Запрошена модификация кода --------

Вопрос: Подсчитайте номер быстрой треугольной серии, который имеет 50 факторов?

Уточнено: Допустим, есть серия

   1 : 1
   3 : 1+2
   6 : 1+2+3 
   10 : 1+2+3+4
   15 : 1+2+3+4+5
   21 : 1+2+3+4+5+6
   28 : 1+2+3+4+5+6+7

здесь 1,3,6,10,15,21,28 — числа, подпадающие под треугольный ряд.

давайте посмотрим на множители числа

    Number factors         Count
    1     : 1               1              
    3     : 1,3             2
    6     : 1,2,3,6         4
    10    : 1,2,5,10        4
    15    : 1,3,5,15        4
    21    : 1,3,7,21        4
    28    : 1,2,4,7,14,28   6

здесь 6 — первое треугольное число, имеющее 4 делителя. даже если 10,15,21 тоже имеют 4 множителя, но они не 1-й. Например, давайте возьмем число за 2, которое имеет 2 множителя как 1 и 2, то же самое для числа 3, также имеющего 2 множителя как 1 и 3.

но в соответствии с вопросом 3 будет ответ, а не 2, потому что 2 не входит в список номеров треугольной серии, даже если он быстрее, чем 3.


person Chandan Kumar    schedule 09.07.2013    source источник
comment
Этот вопрос кажется не по теме, потому что он касается математики, а не программирования.   -  person razlebe    schedule 09.07.2013
comment
Проект Эйлера?   -  person JNF    schedule 09.07.2013
comment
Да, JNF, но мне нужно правильное решение (шаги/логика) для вышеуказанного вопроса. Я получил вывод, но я надеюсь, что можно написать лучший код. Вот почему запрашиваю решение, которое лучше, чем моя данная логика.   -  person Chandan Kumar    schedule 09.07.2013
comment
@razlebe, вопросы по алгоритму разрешены в Stack Overflow.   -  person Lance Roberts    schedule 09.07.2013
comment
См. это для примера лучшего кода.   -  person Corak    schedule 09.07.2013
comment
AFAIR, когда вы отвечаете на вопрос о Project Euler, вам автоматически предоставляется доступ к теме форума, чтобы поделиться своим решением со всем миром и прочитать других. Эти посты — отличный источник лучшей логики.   -  person akalenuk    schedule 09.07.2013
comment
Я повторю свой вопрос прямо к ОП: мы говорим ровно 50 или больше чем 50? Поскольку в задаче проекта Эйлера указано, что первое число треугольника имеет более пятисот делителей.   -  person Corak    schedule 09.07.2013
comment
@lance Даже если это не поддерживается никаким кодом?   -  person razlebe    schedule 09.07.2013
comment
@razlebe - код находится в собственном ответе ОП. Не лучший способ сделать это, но, я думаю, это что-то.   -  person Corak    schedule 09.07.2013


Ответы (4)


Треугольник с номером #2591 = 3357936 — первый, в котором ровно 50 делителей: 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 36, 48. , 54, 72, 81, 108, 144, 162, 216, 324, 432, 648, 1296, 2591, 5182, 7773, 10364, 15546, 20728, 23319, 31092, 41456, 46638, 62184, 69957, 93276, 124368 , 139914, 186552, 209871, 279828, 373104, 419742, 559656, 839484, 1119312, 1678968, 3357936

Номер треугольника #12375 = 76576500 — это первый треугольник, в котором минимум 500 множителей (фактически 576 множителей): 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, . .., 19144125, 25525500, 38288250, 76576500

Номер треугольника #1569375 = 1231469730000 – это первый треугольник, в котором ровно 500 делителей.

Сам код решения очень прост, если вы можете получить делители:

   public static long Solution(int factorsCount) {
      for (long i = 1; ; ++i) {
        long n = i * (i + 1) / 2;

        IList<long> factors = GetDivisors(n);

        // This code tests if a triangle number has exactly factorsCount factors
        // if you want to find out a triangle number which has at least factorsCount factors
        // change "==" comparison to ">=" one:
        // if (factors.Count >= factorsCount)  
        if (factors.Count == factorsCount) 
          return n;
      }
    }

  ...

  long solution = Solution(50);

Если у вас нет подпрограммы для получения числовых множителей, вы можете использовать эту:

// Get prime divisors 
private static IList<long> CoreGetPrimeDivisors(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;
}

/// <summary>
/// Get prime divisors 
/// </summary>
public static IList<long> GetPrimeDivisors(long value, IList<int> primes) {
  if (!Object.ReferenceEquals(null, primes))
    return CoreGetPrimeDivisors(value, primes);

  List<long> results = new List<long>();

  while ((value % 2) == 0) {
    results.Add(2);

    value = value / 2;
  }

  while ((value % 3) == 0) {
    results.Add(3);

    value = value / 3;
  }

  while ((value % 5) == 0) {
    results.Add(5);

    value = value / 5;
  }

  while ((value % 7) == 0) {
    results.Add(7);

    value = value / 7;
  }

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

  for (int i = 2; i <= n; ++i) {
    v = 6 * i - 1;

    if ((value % v) == 0) {
      while ((value % v) == 0) {
        results.Add(v);

        value = value / v;
      }

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

    v = 6 * i + 1;

    if ((value % v) == 0) {
      while ((value % v) == 0) {
        results.Add(v);

        value = value / v;
      }

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

    if (v > threshould)
      break;
  }

  if (value > 1) {
    if (results.Count <= 0)
      results.Add(value);
    else if (value != results[results.Count - 1])
      results.Add(value);
  }

  return results;
}

/// <summary>
/// Get all divisors
/// </summary>
public static IList<long> GetDivisors(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;

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

    hs.Add(p);
  }

  List<long> result = new List<long>();

  result.Add(1);

  var en = hs.GetEnumerator();

  while (en.MoveNext())
    result.Add(en.Current);

  result.Sort();

  return result;
}

/// <summary>
/// Get all divisors
/// </summary>
public static IList<long> GetDivisors(long value) {
  return GetDivisors(value, null);
}
person Dmitry Bychenko    schedule 09.07.2013
comment
Ха, я что-то не так делаю? С моим алгоритмом для 50 я получаю #224 is 25200: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 28, 30, 35, 36, 40, 42, 45, 48, 50, 56, 60, 63, 70, 72, 75, 80, 84, 90, 100, 105, 112, 120, 126, 140, 144, 150, 168, 175, 180, 200, 210, 225, 240, 252, 280, 300, 315, 336, 350, 360, 400, 420, 450, 504, 525, 560, 600, 630, 700, 720, 840, 900, 1008, 1050, 1200, 1260, 1400, 1575, 1680, 1800, 2100, 2520, 2800, 3150, 3600, 4200, 5040, 6300, 8400, 12600, 25200. Тот же алгоритм дает #12375 is 76576500 для 500... - person Corak; 09.07.2013
comment
Подождите... мы говорим ровно 50 или более 50? Поскольку в задаче проекта Эйлера указано, что первое число треугольника имеет более пятисот делителей. - person Corak; 09.07.2013
comment
Просто измените сравнение с == на ›= (см. мои комментарии), и вы обнаружите числа треугольников, которые имеют по крайней мере 50 или 500 делителей. Итак, число треугольника #2591 = 3357936 имеет точно 50 делителей, #1569375 = 1231469730000 имеет ровно 500 делителей, #224 = 25200 имеет не менее 50 делителей (фактически 90) и #12375 = 76576500 имеет не менее 500 делителей (фактически 576). - person Dmitry Bychenko; 09.07.2013

Решение: Позвольте мне разбить Вопрос на несколько модулей.

1) Найдите треугольный ряд до числа.

2) Сохраните все идентифицированные числа в списке целых чисел

3) Найдите количество множителей для определенного числа

4) Переберите каждый элемент треугольного ряда и найдите количество факторов для каждого числа.

5) проверьте первый, чей счет равен 50, затем отобразите значение

6) напишите оператор break, чтобы показать только первое 50-е число.

Программа

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

namespace IsNumberTringularSeriesConsoleApp
{ 
    class Program
    {
        /// <summary>
        /// Listing all numbers comes under Triangular series.
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        static List<int> GetTriangularNumbers(int number)
        {
            List<int> lstTriangularNumbers = new List<int>();
            int i;
            int sum = 0;
            int triangularNumber = 0;
            for (i = 1; i < number; i++)
            {
                sum = sum + i;
                triangularNumber = sum;
                lstTriangularNumbers.Add(triangularNumber);
            }
            return lstTriangularNumbers;
        }

        /// <summary>
        /// returns(count) the number of factors for each number
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static int FactorCount(int number)
        {
            List<int> factors = new List<int>();
            int max = (int)Math.Sqrt(number);  //round down
            for (int factor = 1; factor <= max; ++factor)
            { 
                //test from 1 to the square root, or the int below it, inclusive.
                if (number % factor == 0)
                {
                    factors.Add(factor);
                    if (factor != number / factor)
                   {
                     // Don't add the square root twice!  
                        factors.Add(number / factor);
                   }
                }
            }
            return factors.Count;
        }

        static void Main(string[] args)
        {
            List<int> lstTriangularNumbers = new List<int>();
            List<int> factors = new List<int>();
            int count = 0;
            //Getting the list of numbers comes under triangular series till 5000
            lstTriangularNumbers = GetTriangularNumbers(5000);

            foreach (int number in lstTriangularNumbers)
            {
                /*
                 * Calling the FactorCount(number) function to check no of factors 
                 * available for the specific triangular number - number.
                 */
                 count = FactorCount(number);
                 //Console.WriteLine("No of factors for : " + number + " is : " + count);
                if (count == 50)
                {
                    Console.WriteLine("No of factors for first Triangular Number : " + number + " is : " + count);
                    break;
                }
            }
            Console.ReadLine();
        }
    }
}
person Chandan Kumar    schedule 09.07.2013
comment
@HighPerformanceMark: OP, предположительно, может заменить BigInteger, хотя это может потребовать некоторой работы - person Michael Bray; 09.07.2013
comment
Босс, он выдает результат: количество множителей для первого треугольного числа: 3357936 равно 50, что правильно. Мне нужен лучший код. - person Chandan Kumar; 09.07.2013
comment
Первое, что нужно улучшить: ваши FactorCount и GetFactors в основном имеют одинаковое тело. Так что пусть FactorCount будет return GetFactors(number).Count;. И снова загляните в mathblog, чтобы см. другие способы значительно сократить время выполнения. Или что именно вы подразумеваете под лучшим кодом? - person Corak; 09.07.2013
comment
И я бы изменил GetTriangularNumbers на что-то вроде этого: public static IEnumerable<int> GetTriangularInt32() { var sum = 0; var i = 1; while (Int32.MaxValue - sum >= i) { sum += i++; yield return sum; } }, так как вы все равно foreach и break над ним, вам не нужно заранее создавать ненужные числа. - person Corak; 09.07.2013

вот мой ответ

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

namespace TriangularSeries
{
    class MyClass
    {
        static void Main(string[] args)
        {
            int result;
            TriangularSeries aSeries = new TriangularSeries();
            result = aSeries.TSeries();
            Console.WriteLine("The first Triangular Series number that has 50Factors is : " + result);
            Console.Read();
        }
    }

    //Find the Triangular Series numbers
    class TriangularSeries
    {
        public int TSeries()
        {
            int fCount = 0, T1 = 1, i = 1, T2 = 0, fval = 0;
            while (fCount != 50)
            {
                i += 1;
                T2 = T1 + i;

                fCount = CalcFactors(T1);
                fval = T1;                   
                T1 = T2;

            }
            return fval;
        }

        public int CalcFactors(int num1)
        {

            List<int> factors = new List<int>();
            int max = (int)Math.Sqrt(num1);  //round down
            for (int factor = 1; factor <= max; ++factor)
            {
                //test from 1 to the square root, or the int below it, inclusive.
                if (num1 % factor == 0)
                {
                    factors.Add(factor);
                    if (factor != num1 / factor)
                    {
                        // Don't add the square root twice!  
                        factors.Add(num1 / factor);
                    }
                }
            }
            return factors.Count;

        }
    }   
}
person Community    schedule 30.11.2013
comment
Спасибо за ваше решение блестяще. - person Chandan Kumar; 01.12.2013

Вот моя программа на языке C

#include<stdio.h>
int i;
int num1=0,num2=1;
int a[3000];
int tri_series()         //This function finds the Triangular series numbers
{
    for(i=0;num2<=3000;i++)
    {
    num1=num1+num2;
    a[i]=num1;
    num2++;
    }
}
int main()
{
tri_series();            //Calling the function tri_series
int num,count;
    for(i=0;i<=3000;i++)
    {
      count=0;
      for(num=1;num<=a[i];num++)
      {
        if(a[i]%num==0)  //Finds the factors of each Triangular Series Number 
        count=count+1;   
      }
      if(count==50)      //Break at the first Triangular Series Number having 50 factors
      {
       printf("%d:%d\t",a[i],count);
       break;
      }
    }
}

Проблема с производительностью: этот код создает проблему с производительностью, когда дело доходит до времени выполнения. Выполнение и отображение вывода занимает «минуту».

person Petryanu    schedule 12.12.2013
comment
Спасибо ану. Спасибо за ответ в версии c. Будет полезно для программистов на C. - person Chandan Kumar; 12.12.2013
comment
Но требуется несколько модификаций. num2 не определен, int main не возвращает никакого значения. пожалуйста, измените программу так, чтобы она была полезна для программистов на C. - person Chandan Kumar; 12.12.2013
comment
Значения a[i] печатаются в основной функции, функция tri_series только что определена и вызывается в основной функции. Спасибо за поправку Чандан. - person Petryanu; 13.12.2013