Обчисліть практичні числа


18

Визначення

Позитивне ціле число n- це практичне число (OEIS-послідовність A005153 ), якщо всі менші додатні цілі числа можна представити у вигляді сум різних дільників n.

Наприклад, 18це практичне число: його дільники дорівнюють 1, 2, 3, 6, 9 і 18, а інші додатні цілі числа, менші за 18, можуть утворюватися так:

 4 = 1 + 3          5 = 2 + 3           7 = 1 + 6
 8 = 2 + 6          10 = 1 + 9         11 = 2 + 9
12 = 3 + 9 = 1 + 2 + 9 = 1 + 2 + 3 + 6
13 = 1 + 3 + 9      14 = 2 + 3 + 9      15 = 6 + 9
16 = 1 + 6 + 9      17 = 2 + 6 + 9

Але 14це не є практичним числом: його дільники - 1, 2, 7 і 14, і підмножини їх немає, що додає до 4, 5, 6, 11, 12 або 13.

Виклик

Напишіть програму, функцію або дієслово, яке приймає за вхід додатне ціле число xі повертає або друкує x- й практичний номер, індексований від 1 для узгодження з OEIS. Ваш код повинен бути достатньо ефективним, щоб він міг обробляти вводи до 250000 менш ніж за дві хвилини на розумному настільному комп’ютері. (Зверніть увагу: моя реалізація посилань на Java управляє 250000 менш ніж за 0,5 секунди, а моя контрольна реалізація в Python управляє ним за 12 секунд).

Тестові справи

Input        Expected output
1            1
8            18
1000         6500
250000       2764000
1000000      12214770
3000000      39258256

(ІМХО) це може бути навіть цікаво, якщо виграє найшвидший код (на кожній мові?)
Відобразити ім'я

4
@SargeBorsch Отже, ви побачите таблиці з 250K статей у всіх відповідях
доктор belisarius

@belisarius хороший момент. але я думаю, що таке обман можна легко заборонити. Або проблема може вимагати правильних відповідей на будь-яке число, але тоді виникнуть труднощі, коли це робиться мовою без великих цілих чисел у стандартній бібліотеці ...: /
Відображати ім'я

Я маю на увазі одну алгоритмічну оптимізацію, але з діючими правилами я лінивий її застосовувати: P
Відображати ім'я

4
@SargeBorsch, якщо ви не хочете гольфувати свій код, сміливо завантажуйте його на щось на зразок gist.github.com і опускайте посилання в коментарі тут або в чаті. FWIW Я віддаю перевагу кодовому гольфу з великими обмеженнями продуктивності, щоб найшвидший код з двох причин: по-перше, довжина коду є більш об'єктивно вимірюваною; по-друге, він вводить елемент компромісу: які оптимізації швидкості можна залишити, щоб скоротити код, не руйнуючи продуктивність?
Пітер Тейлор

Відповіді:


5

J (99 знаків)

f=:3 :0
'n c'=.0 1
while.c<y do.
'p e'=.__ q:n=.n+2
c=.c+*/(}.p)<:}:1+*/\(<:p^e+1)%<:p
end.
n+n=0
)

Оскільки постановка проблеми вимагає "програми, функції або дієслова ", хтось повинен був зробити J подання. J люди помітять, що я насправді не гольф (!) Чи оптимізував це. Як і інші записи, я використовував теорему Стюарта, згадану на посиланні OEIS, щоб перевірити, чи є кожне парне число практичним чи ні.

У мене немає готового доступу до "розумного настільного комп'ютера" з встановленим J. У моєму шестирічному нетбуку f 250000обчислюється за 120,6 секунди, що не зовсім за дві хвилини, але, мабуть, на будь-якому трохи більш розумному комп'ютері це закінчується в часі.


6

Математика, 126 121 чол

Завдяки belisarius.

Використання формули у вікіпедії.

f=(i=j=1;While[j<#,If[And@@Thread[#[[;;,1]]<2+Most@DivisorSum[FoldList[#Power@@#2&,1,#],#&]&@FactorInteger@++i],j++]];i)&

Приклади:

f[1]

1

f[8]

18

f[250000]

2764000

Вирахування f[250000]на моєму комп’ютері знадобилося 70-х .


3
Я думаю, що ви можете отримати кращі показники за рахунок одного
знака,

1
Зменшуючи код від подання OEIS, ви сповільнили виконання в 10 разів. Просто цікаво: "чому ти вважаєш, що ваш код працює набагато повільніше, ніж приклад OEIS?"
DavidC

@belisarius Ваша пропозиція скорочує навпіл час, як очікувалося.
DavidC

2
Те саме в 119 символах:(i=j=1;While[j<#,If[And@@Thread[#[[;;,1]]<2+Most@DivisorSum[FoldList[#Power@@#2&,1,#],#&]&@FactorInteger@++i],j++]];i)&
Доктор Белісарій

3

Хаскелл - 329

s 1=[]
s n=p:(s$div n p)where d=dropWhile((/=0).mod n)[2..ceiling$sqrt$fromIntegral n];p=if null d then n else head d
u=foldr(\v l@((n,c):q)->if v==n then(n,c+1):q else(v,1):l)[(0,1)]
i z=(z<2)||(head w==2)&&(and$zipWith(\(n,_)p->n-1<=p)(tail n)$scanl1(*)$map(\(n,c)->(n*n^c-1)`div`(n-1))n)where w=s z;n=u w
f=((filter i[0..])!!)

Приклади:

> f 1
1
> f 13
32
> f 1000
6500

Ось невеликий набір тестування (додайте до вищезазначеного):

import Data.Time.Clock
import System.IO

test x = do
    start <- getCurrentTime
    putStr $ (show x) ++ " -> " ++ (show $ f x)
    finish <- getCurrentTime
    putStrLn $ " [" ++ (show $ diffUTCTime finish start) ++ "]"

main = do
    hSetBuffering stdout NoBuffering
    mapM_ test [1, 8, 1000, 250000, 1000000, 3000000]

Результати тесту після складання з ghc -O3:

1 -> 1 [0.000071s]
8 -> 18 [0.000047s]
1000 -> 6500 [0.010045s]
250000 -> 2764000 [29.084049s]
1000000 -> 12214770 [201.374324s]
3000000 -> 39258256 [986.885397s]

Коли я пробую це в ghci, він скаржиться parse error on input `='. Чи потрібно використовувати якийсь прапор чи інший?
Пітер Тейлор

1
@PeterTaylor Ви не можете вставити визначення функції в ghci, як це. Найпростіше - зберегти його asdf.hsта запустити ghci asdf.hs, а звідти ви зможете отримати доступf
mniip

@PeterTaylor ghc --make -O3 [filename]. Ви також можете завантажити його в ghci, :l [filename]але, враховуючи встановлені часові обмеження, мабуть, найкраще. :)
Джонатан Ван Матре

@JonathanVanMatre, як видно з вищевказаного коментаря, ghciзавантажує файли, вказані в його аргументах
mniip

Добренько. Тим часом я розпочав роботу з вашими тестовими рамками та ghc. Ваш комп'ютер швидший, ніж мій, але він все ще чудово відповідає критерію продуктивності на моєму комп’ютері за 98 секунд.
Пітер Тейлор

2

Javascript, 306 307 282B

function y(r){for(n=r-1,k=1;n;k++)if(p=[],e=[],c=0,P=s=1,!((x=k)%2|1==x)){while(x>1){for(f=x,j=2;j<=Math.sqrt(f);j++)if(f%j==0){f=j;break}f!=p[c-1]?(p.push(f),e.push(2),c++):e[c-1]++,x/=f}for(i=0;c>i;i++){if(p[i]>P+1){s=0;break}P*=(Math.pow(p[i],e[i])-1)/(p[i]-1)}s&&n--}return k-1}

250k в прибл. 6s на моєму ноутбуці.

Коментований код без гольфу: http://jsfiddle.net/82xb9/3/ зараз із кращим сигма-тестуванням та кращим умовою (спасибі коментарі)

Попередня редакція версій: http://jsfiddle.net/82xb9/ http://jsfiddle.net/82xb9/1/


Питання не поставити для функції або програми (JS не має дієслів), тому замість того , беручи до уваги перший рядок ви повинні обернути другий рядок в оголошенні функції і замінити остаточний k--;з return k-1. Незважаючи на те, що трохи збільшує кількість байт, ви можете заощадити кілька з речами , як заміна p[i]>=P+2з p[i]>P+1(і , можливо , шляхом видалення виклику внутрішньої функції і використовуючи breakзамість цього).
Пітер Тейлор

Я думаю, що частина «тестування сигми» може бути переписана як для розміру, так і для швидкості: jsfiddle.net/3DTSa . Хоча це рішення JS дуже швидко, як є.
користувач2846289
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.