nの除数で最小の整数を効率的に計算する


9

この問題に取り組むために、私は最初にそれを観察しました

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

ここで、ϕ(m)約数(必ずしも素数ではない)の約数ですmmϕ(m)=nとなるような最小の整数の場合、

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

ここで、i p e i iが最小になるように選択する必要があります。pの選択は簡単です-それらは昇順の単なる素数です。eiipieip

しかし、を選択するための最初の考えeiは正しくありませんでした。私は単にn因数分解し、降順で因数をソートして1を引くことができると思いました。ほとんどの場合、これはうまく機能します。たとえば、n=15除数の最小の整数は次のとおりです。

15 = 4 + 1 )、 2 + 1 M = 2 4 3 2 = 144

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

しかし、これは正しくありません。n=16

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

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

正解は次のとおりです。

m = 2 3 3 1 5 1 = 120

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

したがって、ファクターをマージする必要があることは明らかです。この場合、です。しかし、クリーンで直接的なマージ戦略は正確にはわかりません。たとえば、常に2のべき乗に統合する必要があると考えるかもしれませんが、これは正しくありません。71>222

m = 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

回答:


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

nnO(n)O(n2logn)n

O(nlogn)powerset

:私は、これは、動的プログラミング使用して効率的に実装することが容易であると考えていgist.github.com/orlp/0fbb7784782712bc7c411aa58a188143いくつかの点ネジのもので浮動小数点限ら精度の意志-私は道で本当に対数トリックに慣れていないんだが。とはいえ、これはすべての乗法パーティションを生成するよりも実際には高速だとは思いません。実際、私はそれがまさに変装していることだと信じています!
orlp

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

1
multiplicative_partitions(24)[4, 3, 2][6, 2, 2]2332512531512332=72<2531=96

-1

2a·3b·5c...

27·323·3323·3·52·3·5·723·3·5=120

2pq12p1·3q1

2ab12ab1>2a1·xb12323<2·7ます。


3
許してください、しかしこれは私の質問には全く答えません、それは私の質問で見つけたものを要約するだけです。タイトルはそれだけです。タイトルではなく、質問自体です。答える前にタイトルだけ読んだような気がします。本当の質問は私の質問文の一番下にあります。
orlp 2016

それは最後の段落で答えられています。
gnasher729 2016

@ gnasher729それは、「効率的に計算する」、または「マージのための最適な戦略」の質問への答えになるにはほど遠い
yo '
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.