Найти количество N-значных чисел, у которых сумма цифр равна их произведению (оптимизировать код)

Нужно: Найти количество N-значных чисел, у которых сумма цифр равна их произведению (оптимизировать код)

Моя неудачная попытка (Код медленный):

def cond(a):
    sum = 0
    mult = 1
    while a > 0:
        mult *= a % 10
        sum += a % 10
        a = int(a / 10)

    return sum == mult


def foo(n):
    n = int(n)
    if n == 1:
        return "10 0"

    req_num = 10**n
    prev_num = 10**(n-1)

    min_num = None
    counter = 0

    for i in range(prev_num, req_num):
        if cond(i):
            print(i)
            counter += 1
            if min_num is None:
                min_num = i

    return str(counter) + " " + str(min_num)


print(foo(3))

Для 8-значных и выше чисел не справляется. Как можно улучшить алгоритм? Я нагуглил решение этой проблемы на C++, но не могу перевести код на Python и вообще понять алгоритм, который там используется: https://www.cyberforum.ru/cpp-beginners/thread1972973.html Буду очень благодарен, если кто-то детально опишет используемый там алгоритм. Понял только то, что там как-то используются сочетания к отсортированным числам, благодаря чему количество вычислений уменьшается.


Ответы (2 шт):

Автор решения: Qwertiy

Упростил:

  1. Если n=1, то все 10 чисел являются искомыми, минимальное - 0.
  2. Перебираем все наборы чисел от 1 до 9 включительно.
  3. Если количество цифр n, а их сумма и произведение равны n, то увеличиваем ответ на число перестановок с повторениями для данного набора.
  4. Делаем отсечение по достижению или превышению произведения и по слишком маленькой сумме.
  5. Первый найденный набор образует минимальное число.

Изначальный алгоритм:

  1. Перебираем все различные наборы чисел от 2 до 9 (включительно), произведение которых равно n, а сумма - количеству чисел в наборе (обозначим k).
  2. Для каждого такого набора чисел считаем число сочетаний из n по k и умножаем на количество различных перестановок с повторениями для данного набора.
  3. Суммируем все числа из прошлого пункта.

Ещё есть особый случай - для однозначных чисел решением является ещё и 0.

→ Ссылка
Автор решения: AndroID

Вышел такой код. Следуя ответу @Quertiy, можно сделать лучше, но не знаю как.

def check(number):
    s, m = 0, 1
    for digit in str(number) :
        digit = int(digit)
        s += digit
        m *= digit
    return s == m

# input n
while True :
    n = input("Введите N: ")
    if n.isdigit() :
        n = int(n)
        break
    else :
        print("Допустимы только натуральные числа!")

numbers = range(int("1" * n), int("1" + "0" * n))
numbers = filter(lambda x: "0" not in str(x), numbers)
numbers = tuple(filter(lambda x: check(x), numbers))

print(len(numbers))

Пример:

Введите N: 8
224
→ Ссылка