Tính toán hiệu quả số nguyên nhỏ nhất với n ước số


9

Để giải quyết vấn đề này, trước tiên tôi đã quan sát thấy rằng

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

Trong đó là số ước (không nhất thiết là số nguyên tố) của . Nếu là số nguyên nhỏ nhất sao cho , thìϕ(m)mmϕ(m)=n

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

Bây giờ chúng ta phải chọn sao cho là tối thiểu. Các lựa chọn cho là tầm thường - chúng chỉ là các số nguyên tố theo thứ tự tăng dần.eiipieip

Tuy nhiên, suy nghĩ đầu tiên của tôi khi chọn là không chính xác. Tôi nghĩ bạn có thể chỉ cần yếu tố , sắp xếp các yếu tố theo thứ tự giảm dần và trừ đi 1. Hầu hết thời gian này hoạt động tốt, ví dụ: số nguyên nhỏ nhất có ước là:einn=15

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

Nhưng điều này không đúng với :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

Trong khi đó, câu trả lời đúng là:

m = 2 3 3 1 5 1 = 120

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

Vì vậy, rõ ràng đôi khi chúng ta cần hợp nhất các yếu tố. Trong trường hợp này vì . Nhưng tôi không thấy chính xác một chiến lược hợp nhất trực tiếp và rõ ràng. Ví dụ, người ta có thể nghĩ rằng chúng ta phải luôn hợp nhất thành sức mạnh, nhưng điều này không đúng: 271>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

Tôi không thể nghĩ ngay đến một ví dụ, nhưng bản năng của tôi nói rằng một số cách tiếp cận tham lam có thể thất bại nếu họ hợp nhất các quyền hạn trước.

Có một chiến lược tối ưu đơn giản để hợp nhất các quyền hạn này để có câu trả lời chính xác?


Phụ lục. Một thuật toán tham lam kiểm tra mọi hợp nhất có thể và thực hiện tốt nhất trên cơ sở hợp nhất theo hợp nhất, không thành công trên . Chuỗi hợp nhất từng cái một là:n=3072

22315171111131171191231291311

23325171111131171191231291

25335171111131171191231

Tuy nhiên, giải pháp tối ưu là:

27335271111131171191

@orlp: Đề xuất của tôi là: fix (giả sử, ) và sửa (nói, ). Sau đó, bạn đang cố gắng giảm thiểu , theo . Vì vậy, bằng cách làm việc với một số cố định (số nguyên tố), bạn có thể bỏ qua các biến chứng về việc liệu một số nguyên tố nhất định có xuất hiện ở mức tối thiểu toàn cầu hay không. Bạn tìm mức tối thiểu cho mỗi , sau đó lấy min của những cái đó. 24 m 2 k 1 log ( 2 ) + k 2 log ( 3 ) k 1 k 2 = 24 m mn24m2k1log(2)+k2log(3)k1k2=24mm
Steve D

Câu trả lời:


1

Đây là một giải pháp, dựa trên ý kiến ​​của tôi ở trên. Tôi không tuyên bố điều này là tối ưu.

Ý tưởng là xem xét , mà chúng tôi định nghĩa là "số nguyên dương nhỏ nhất với chính xác ước và các thừa số nguyên tố riêng biệt". Chúng tôi thực hiện các quan sát dễ dàng:n mT(n,m)nm

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

Và chúng tôi cũng có sự tái phát:

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

Cuối cùng, số lượng bạn đang tìm kiếm là

min1ilog(n)T(n,i)

Cuối cùng, đây là một số mã Python, đồng ý với tất cả các số bạn đã đưa ra ở trên. Lưu ý rằng nó hoạt động với các logarit để giữ cho các số nhỏ hơn: vì vậy số nguyên thực tế bạn tìm kiếm là 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))

Các ý kiến ​​bạn đề cập dường như đã bị xóa một cách đáng tiếc, nhưng điều này chắc chắn là tối ưu (theo nghĩa là tính toán số nguyên nhỏ nhất có thể có chính xác yếu tố). Có phải đó là sự tối ưu của sự phức tạp thời gian mà bạn không chắc chắn? Tôi không biết ràng buộc chặt chẽ về số lượng ước của một số nguyên , nhưng ngay cả với giới hạn rất bi quan của thuật toán của bạn chỉ là , nên đủ nhanh để trong hàng vạn! (BTW: Tôi đã viết cùng một thuật toán (trừ một số tối ưu hóa) nhưng bạn đã đến đó trước, hoàn thành tốt!)nnO(n)O(n2logn)n
j_random_hacker

@j_random_hacker: Vâng, không chắc điều gì đã xảy ra với những bình luận đó: có rất nhiều trong số họ, và giờ họ đã biến mất! Tôi đã thực sự nói về sự phức tạp thời gian; Tôi thực sự nghĩ rằng nó có thể gần với , nhưng số lượng ước là một hàm khó. Tất nhiên, mã ở trên chắc chắn có thể được tối ưu hóa tốt hơn: chẳng hạn như tài khoản cho các bản sao. O(nlogn)powerset
Steve D

Tôi tin rằng điều này dễ thực hiện hơn khi sử dụng lập trình động: gist.github.com/orlp/0fbb7784782712bc7c411aa58a188143 Tôi thực sự không thoải mái với thủ thuật logarit bằng cách nào đó - độ chính xác giới hạn điểm nổi sẽ ở một số điểm. Điều đó đang được nói, tôi không tin rằng điều này thực sự nhanh hơn việc tạo ra tất cả các phân vùng nhân. Trên thực tế, tôi tin rằng đó chính xác là những gì nó đang ngụy trang!
orlp

Sau khi đọc nhận xét của @ orlp và mã của bạn chặt chẽ hơn, bây giờ tôi nghĩ điều quan trọng đối với độ phức tạp thời gian (và hiệu suất thực tế) để thay đổi for factor_list in powerset(factors)thành thứ gì đó tạo ra mỗi ước số riêng biệt của nchính xác một lần. Bằng cách đó, giả sử, , khi bạn coi các giải pháp chứa chính xác các số nguyên tố đầu tiên là các thừa số nguyên tố riêng biệt của chúng, bạn sẽ chỉ thực hiện công việc không đệ quy thay vì , theo cấp số nhân tính theo . n=2k3k2kO(k2)O((2kk))k
j_random_hacker

1
@orlp: Tôi hiểu nhầm thuật ngữ "phân vùng nhân", xin lỗi. Cảm ơn mã Python. Để xem tại sao thuật toán của Steve D không song song với mã đó, hãy xem xét multiplicative_partitions(24), nó tạo ra (trong số các phân vùng khác) các phân vùng [4, 3, 2][6, 2, 2](sau khi đảo ngược thứ tự để đưa ra thừa số nguyên tố nhỏ nhất theo cấp số nhân cao nhất) tương ứng với các giải pháp và , tương ứng. Thuật toán của Steve D sẽ không bao giờ xem xét giải pháp sau, vì nó đã xác định rằng phép trừ . 2332512531512332=72<2531=96
j_random_hacker

-1

Các ứng cử viên có thể cho "số nguyên nhỏ nhất với n ước" là các số nguyên có dạng trong đó a ≥ b ≥ c ... và (a + 1) (b + 1) (c + 1) ... = n.2a·3b·5c...

Vì vậy, bạn cần tìm mọi cách để biểu thị n là tích của số nguyên ≥ 2 theo thứ tự không tăng dần, và tính toán và kiểm tra các ứng cử viên tương ứng. Ví dụ: khi n = 16, 16 = 8 · 2 = 4 · 4 = 4 · 2 · 2 = 2 · 2 · 2 · 2, vì vậy khả năng là , , , và nhỏ nhất là .27·323·3323·3·52·3·5·723·3·5=120

Nếu n là tích của hai số nguyên tố p · q, p ≥ q, thì các ứng cử viên duy nhất là và , và số sau luôn nhỏ hơn .2pq12p1·3q1

Ví dụ, bạn có thể tìm ra một số điều kiện khi có thể có một yếu tố , bằng cách kiểm tra xem đối với một số số nguyên tố x không phải là một yếu tố. Trong ví dụ n = 16, có một yếu tố vì .2ab12ab1>2a1·xb12323<2·7


3
Xin lỗi, nhưng điều này không trả lời câu hỏi của tôi chút nào, nó chỉ tóm tắt những gì tôi tìm thấy trong câu hỏi của mình. Tiêu đề chỉ là: một tiêu đề, không phải chính câu hỏi. Tôi cảm thấy như bạn chỉ đọc tiêu đề trước khi trả lời. Câu hỏi thực sự nằm ở cuối văn bản câu hỏi của tôi.
orlp

Điều đó được trả lời trong đoạn cuối.
gnasher729

@ gnasher729 Đó không phải là một câu trả lời cho câu hỏi "tính toán hiệu quả" hay thậm chí là "chiến lược tối ưu để hợp nhất"
yo '
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.