К основному контенту

Задача 12.Треугольное число с большим количеством делителей


Условие задачи 

Последовательность треугольных чисел образуется путем сложения натуральных чисел. К примеру, 7-ое треугольное число будет 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. Первые десять треугольных чисел:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Перечислим делители первых семи треугольных чисел:
 1: 1
 3: 1,3
 6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
Как мы видим, 28 - первое треугольное число, у которого более пяти делителей.
Каково первое треугольное число, у которого более пятисот делителей?

Решение 

Задача состоит из 2-х этапов:
- Этап 1. Собственно генерация числа
- Этап 2. Поиск делителей или на математическом языке "факторизация числа.



С этапом 1 особых проблем не возникло. Достаточно применить следующую конструкцию:
 
num=sum([c for c in range(1,x+1)])

То есть генерируем список чисел и суммируем данный список.В цикле увеличиваем x.
А вот с факторизацией проблемы. Для нашего объема задачи 500 делителей неподъемная величина если тупо перебирать делители. В математике я не силен, но мне попался ресурс где подробно описан оптимальный алгоритм факторизации: 

1. Первоначальное количество делителей = 2 (чтобы не перебирать 1 и само число) 
2. Делители рассматриваем в промежутке от 2 до квадратного корня числа.
3. При нахождении делителя увеличиваем их количество на 2 (т.к делители всегда ходят парами)
4. Если число представляет собой точный квадрат (имеет целый корень) уменьшаем результирующее количество делителей на 1. 

Для начала реализуем функцию определения точного квадрата.
Проблема в том, что результат корня числа в Python всегда float и определить целый ли корень задача усложнена. Я решил эту проблему в лоб - если округленный корень числа в квадрате = изначальному числу число точный квадрат

import math

def is_perf_sq(n):
    x=math.ceil((math.sqrt(n)))
    if x*x==n:
        return True
    else:
        return False

Далее функция, возвращающая первое треугольное число
def max_triangular(m):
    x=3
    n=2
    while n<=m:
        n=2
        num=sum([c for c in range(1,x+1)])
        for i in range(2,math.ceil(math.sqrt(num))):
            if num%i==0:
                n+=2
        if is_perf_sq(num):
                n-=1
        x+=1
    return num

print(max_triangular(500))

Если тупой перебор делителей не завершался и за час, то эта конструкция возвращает результат за 20 секунд.

Популярные сообщения из этого блога

Задача №3 Наибольший простой делитель

Условие задачи Простые делители числа 13195 - это 5, 7, 13 и 29. Каков самый большой делитель числа 600851475143, являющийся простым числом? Решение Простым числом, является натуральное число больше единицы, которое имеет 2 делителя - 1 и само себя.  Для начала найдем все простые делители необходимого числа.  Чтобы сократить поиск будем перебирать до квадратного корня  600851475143 округленного вверх  ( функцией  math.ceil) Перебор будем вести начиная с числа 3. Если i делит число на цело, рекурсивно обращаемся к функции issimple c аргументом i. Функция issimple возвращает пустой список если число является простым. В этом случае число попадает в результирующий список Далее остается только вернуть максимальное значение массива простых чисел, которые нацело делят число 600851475143  Код Python import math def issimple(a): r=math.ceil(math.sqrt(a)) lst=[] for i in range(3,r): if a%i==0: if issimple(i)==[]: lst.app

Задача №1 Сумма чисел, кратных 3 м и 5-ти

 . Задача №1 Если выписать все натуральные числа меньше 10, кратные 3 или 5, то получим 3, 5, 6 и 9. Сумма этих чисел - 23. Найдите сумму всех чисел меньше 1000, кратных 3 или 5. Решение

Задача 21. Дружественные числа

Пусть d( n ) определяется как сумма делителей  n  (числа меньше  n , делящие  n  нацело). Если d( a ) =  b  и d( b ) =  a , где  a  ≠  b , то  a  и  b  называются дружественной парой, а каждое из чисел  a  и  b  - дружественным числом. Например, делителями числа 220 являются 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 и 110, поэтому d(220) = 284. Делители 284 - 1, 2, 4, 71, 142, поэтому d(284) = 220. Подсчитайте сумму всех дружественных чисел меньше 10000. Решение Для начала определим функцию, которая будет возвращать сумму делителей числа: def get_sum(n):     s=0     for i in range(1,n):         if n%i==0:             s+=i     return s Думаю не требует объяснений все довольно тривиально Далее определяем функцию, возвращающую список дружественных чисел до числа n:   def gen_friendlys(n):     res=[]     for i in range(1,n):         if i not in res:             tmp=get_sum(i)             if i==get_sum(tmp) and i!=tmp:                 res.append(i)                 res.