有效计算n个除数的最小整数


9

为了解决这个问题,我首先观察到

ϕ(p1e1 p2e2 pkek)=(e1+1)(e2+1)(ek+1)

其中ϕ(m)是的(不一定是素数)的除数数m。如果m是使得的最小整数ϕ(m)=n,则

ϕ(m)=n
(e1+1)(e2+1)(ek+1)=n

现在,我们必须选择ei这样ipiei是最小的。的选择p很简单-它们只是升序的质数。

然而,我的选择首先想到的ei是不正确的。我以为您可以简单地将n分解为因子,然后按降序对因子进行排序,然后减去1。在大多数情况下,它可以正常工作,例如n=15除数的最小整数是:

15=53
15=(4+1)(2+1)
m=2432=144

但这对于是不正确的n=16

16 = 1 + 1 1 + 1 1 + 1 1 + 1 = 2 1 3 1 5 1 7 1 = 210

16=2222
16=(1+1)(1+1)(1+1)(1+1)
m=21315171=210

正确的答案是:

= 2 3 3 1 5 1 = 120

16=(3+1)(1+1)(1+1)
m=233151=120

很明显,有时候我们需要合并因素。在这种情况下,因为。但是我没有完全看到一种干净直接的合并策略。例如,有人可能认为我们必须始终合并为2的幂,但这是不正确的:71>222

= 2 96 3 1 5 1 7 1 11 1 > 2 96 3 3 5 1 7 1

1552=(96+1)(1+1)(1+1)(1+1)(1+1)
m=296315171111>296335171

我不能立即想到一个例子,但是我的直觉是,如果某些贪婪的方法首先合并了错误的权力,它们可能会失败。

是否有一个简单的最佳策略来合并这些能力以获得正确答案?


n=3072

22315171111131171191231291311

23325171111131171191231291

25335171111131171191231

但是,最佳解决方案是:

27335271111131171191

n24m2k1log(2)+k2log(3)k1k2=24mm

Answers:


1

根据我上面的评论,这是一个解决方案。我没有主张这是最佳选择。

T(n,m)nm

T(n,1)=2n1T(2m,m)=p1p2pm

而且我们也有复发:

T(n,m)=mind|n[T(nd,m1)pmd1]

最后,您要寻找的数量是

min1ilog(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))

您所引用的注释似乎不幸被删除了,但这无疑是最佳选择(就计算正好为因子的最小可能整数而言)。您不确定时间复杂度的最优性吗?我不知道整数的除数的严格限制,但是即使非常悲观,您的算法也只有,对于数以万计!(顺便说一句:我正在编写相同的算法(减去一些优化),但是您首先做到了,做得很好!)n O n O n 2 log n nnnO(n)O(n2logn)n
j_random_hacker

@j_random_hacker:是的,不确定这些评论发生了什么:它们很多,现在都消失了!我确实在谈论时间复杂性;我实际上认为它可能更接近,但是除数的数量是一个棘手的函数。当然,上面的代码当然可以优化得更好:例如,不考虑重复项。O(nlogn)powerset
史蒂夫·D

我相信使用动态编程更容易有效地实现这一点:gist.github.com/orlp/0fbb7784782712bc7c411aa58a188143顺便说一句,我真的不满意对数技巧-浮点有限的精度有时会导致一些麻烦。话虽如此,我不认为这实际上比生成所有乘法分区要快。实际上,我相信这正是变相的做法!
orlp

for factor_list in powerset(factors)nn=2k3k2kO(k2)O((2kk))k

1
@orlp:我误解了“乘法分区”一词,对不起。感谢您的Python代码。要了解Steve D的算法为何不并行执行该代码,请考虑multiplicative_partitions(24),它会生成(和其他)分区[4, 3, 2][6, 2, 2],后者(在反转顺序以使最小素数具有最高指数后)对应于解决方案和。Steve D的算法将永远不会考虑后一种解决方案,因为它已经确定子解决方案。2332512531512332=72<2531=96
j_random_hacker

-1

“具有n个除数的最小整数”的可能候选形式为的整数,其中a≥b≥c ...和(a + 1)(b + 1) (c + 1)... = n。2a·3b·5c...

因此,您需要找到所有方法以非升序形式将n表示为整数≥2的乘积,并计算并检查相应的候选者。例如,当n = 16,16 = 8·2 = 4·4 = 4·2·2 = 2·2·2·2,所以可能性是,,,,最小是。27·323·3323·3·52·3·5·723·3·5=120

如果n是两个素数p·q的乘积,p≥q,则唯一的候选项是和,后者总是较小。2pq12p1·3q1

例如,可以通过检查某些因素是否为来找出可能存在因子的某些情况。素数x不是一个因素。在示例n = 16中,因数是因为。 2 a b 1 > 2 a 1 · x b 1 2 3 2 3 < 2 · 72ab12ab1>2a1·xb12323<2·7


3
原谅我,但这根本不能回答我的问题,它只是总结了我在问题中发现的内容。标题就是:标题,而不是问题本身。我觉得您在回答之前只读过标题。真正的问题在我的问题文本的底部。
orlp

最后一段回答了这一点。
gnasher729

@ gnasher729这远不是一个问题的答案“有效地计算”,甚至为“用于合并最优策略”
哟,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.