上記の私のコメントに基づく解決策は次のとおりです。これが最適であると私は主張しません。
T(n,m)nm
T(n,1)T(2m,m)=2n−1=p1p2⋯pm
そして、私たちにも再発があります:
T(n,m)=mind|n[T(nd,m−1)⋅pd−1m]
min1≤i≤⌈log(n)⌉T(n,i)
そのために、ここにいくつかのPythonコードがあります。これは、上記で指定したすべての数値と一致します。対数と連携して数値を小さく保つことに注意してください。したがって、実際に求める整数はround(2**smallest(n))
です。
import functools
import itertools
import math
# All primes less than 100.
PRIMES = [
2, 3, 5, 7, 11,
13, 17, 19, 23, 29,
31, 37, 41, 43, 47,
53, 59, 61, 67, 71,
73, 79, 83, 89, 97,
]
LOG_PRIMES = [math.log2(p) for p in PRIMES]
def smallest(n):
max_factors = math.ceil(math.log2(n))
min_so_far = float('Infinity')
factors = factorize(n)
memo = {}
for i in range(1, max_factors+1):
t = T(n,i, factors, memo)
if 0.0 < t < min_so_far:
min_so_far = t
return min_so_far
def T(n, m, factors=None, memo=None):
if memo is None:
memo = {}
if n < 2 or m < 1:
return 0
elif m == 1:
# Everything on the smallest prime.
return (n-1) * LOG_PRIMES[0]
elif n < 2**m:
return 0
elif n == 2**m:
# Product of first m primes, in log.
return sum(LOG_PRIMES[:m])
elif (n,m) in memo:
return memo[(n,m)]
if factors is None:
factors = factorize(n)
if len(factors) < m:
return 0
smallest = float('Infinity')
for factor_list in powerset(factors):
divisor = product(factor_list)
first = T(divisor, m-1, factor_list, memo)
# No such product.
if first < 1.0:
continue
second = (n/divisor - 1) * LOG_PRIMES[m-1]
total = first + second
if total < smallest:
smallest = total
memo[(n,m)] = smallest
return smallest
def product(nums):
return functools.reduce(lambda x,y: x*y, nums, 1)
def factorize(n):
prime_factors = []
for p in PRIMES:
while n%p == 0:
n //= p
prime_factors.append(p)
if n == 1:
break
return prime_factors
def powerset(lst):
# No empty set.
return itertools.chain.from_iterable(itertools.combinations(lst, r)
for r in range(1, len(lst)+1))