Pratik sayıları hesaplama


18

Tanım

Pozitif bir tamsayı n, daha küçük pozitif tamsayıların farklı bölenlerinin toplamı olarak gösterilebildiği durumlarda , pratik bir sayıdır ( OEIS sekansı A005153 ) n.

Örneğin, 18pratik bir sayıdır: bölgeleri 1, 2, 3, 6, 9 ve 18'dir ve 18'den küçük diğer pozitif tamsayılar aşağıdaki gibi oluşturulabilir:

 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

Ancak 14pratik bir sayı değildir: bölenleri 1, 2, 7 ve 14'tür ve bunların 4, 5, 6, 11, 12 veya 13'e ekleyen alt kümeleri yoktur.

Meydan okuma

Giriş olarak pozitif bir tamsayı alan xve OEIS ile tutarlılık için 1'den indekslenen x'inci pratik sayıyı döndüren veya basan bir program, işlev veya fiil yazın . Kodunuz, makul bir masaüstü bilgisayarda iki dakikadan daha kısa sürede 250000'e kadar girişleri işleyebilecek kadar verimli olmalıdır. (Java'daki başvuru uygulamam 250000'ü 0,5 saniyeden daha kısa sürede, Python'daki referans uygulamam ise 12 saniyede yönetiyor).

Test senaryoları

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

(IMHO) en hızlı kod (dil başına?)
Görünen Ad

4
@SargeBorsch Yani tüm cevaplar 250K giriş tabloları göreceksiniz
Dr. belisarius

@belisarius iyi bir nokta. ama bence böyle bir hile kolayca yasaklanabilir. Ya da sorun herhangi bir sayı için doğru cevaplar gerektirebilir , ancak daha sonra standart kütüphanede büyük tamsayıları olmayan bir dilde yapıldığında zorluklar yaşanabilir ...: /
Görünen Ad

Aklımda bir algoritmik optimizasyon var, ancak mevcut kurallara göre bunu uygulamak için çok tembelim: P
Görünen Ad

4
@SargeBorsch, eğer kodunuzu golf yapmak istemiyorsanız, kodu gist.github.com gibi bir şeye yüklemekten çekinmeyin ve bir yorumda veya sohbette bir bağlantı bırakın. FWIW İki nedenden dolayı en hızlı koda cömert performans kısıtlamaları olan kod golfünü tercih ediyorum: ilk olarak, kodun uzunluğu daha objektif olarak ölçülebilir; ikincisi, bir takas unsuru sunar: performansı bozmadan kodu kısaltmak için hangi hız optimizasyonları bırakılabilir?
Peter Taylor

Yanıtlar:


5

J (99 karakter)

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
)

Sorun ifadesi bir "program, fonksiyon veya fiil " istediğinden, birisinin J sunması gerekiyordu. J insanlar gerçekten golf (!) Ya da bunu optimize etmediğini fark edecektir. Diğer girişler gibi, OEIS bağlantısında bahsedilen Stewart teoremini, her çift sayının pratik olup olmadığını test etmek için kullandım.

J'nin yüklü olduğu bir "makul masaüstü bilgisayara" hazır erişimim yok. Altı yaşındaki netbook'umda f 250000, iki dakikadan az olmayan 120,6 saniyede hesaplanıyor, ancak muhtemelen zaman içinde biten biraz daha makul bir bilgisayarda.


6

Mathematica 126 121 karakter

Belisarius'a teşekkürler.

Vikipedi'de formül kullanma.

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

Örnekler:

f[1]

1

f[8]

18

f[250000]

2764000

f[250000]Bilgisayarımda hesap yapmak 70'leri aldı .


3
Garip tam sayıları atlayarak bir karakter pahasına daha iyi performans elde edebileceğinizi düşünüyorum
Dr.Belisarius

1
OEIS gönderimindeki kodu azaltarak yürütmeyi 10 kat yavaşlattınız. "Kodunuzun neden OEIS örneğinden çok daha yavaş çalıştığını düşünüyorsunuz?"
DavidC

@belisarius Öneriniz beklendiği gibi zamanı yarıya indiriyor.
DavidC

2
119 karakterde de aynı:(i=j=1;While[j<#,If[And@@Thread[#[[;;,1]]<2+Most@DivisorSum[FoldList[#Power@@#2&,1,#],#&]&@FactorInteger@++i],j++]];i)&
Dr. belisarius

3

Haskell - 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..])!!)

Örnekler:

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

İşte küçük bir test paketi (yukarıdakilerin başına):

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]

Aşağıdakilerle derlendikten sonra test sonuçları 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]

Bunu ghci denediğimde şikayet ediyor parse error on input `='. Bayrak veya başka bir şey kullanmam gerekir mi?
Peter Taylor

1
@PeterTaylor İşlev tanımlarını ghci'ye böyle yapıştıramazsınız. Yapabileceğiniz en basit şey onu kaydetmek asdf.hsve çalıştırmaktır ghci asdf.hs, oradan oradan erişebilirsinizf
mniip

@PeterTaylor ghc --make -O3 [filename]. Ayrıca ghci ile yükleyebilirsiniz, :l [filename]ancak derlenen zaman kısıtlamaları göz önüne alındığında muhtemelen en iyisidir. :)
Jonathan Van Matre

Yukarıdaki yorumda görüldüğü gibi ghci
@JonathanVanMatre

Ah tamam. Bu arada bunu test çerçevenizle çalıştırıyorum ve ghc. Bilgisayarınız benimkinden daha hızlı, ancak hala 98 saniyede bilgisayarımdaki performans kriterinin içinde.
Peter Taylor

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}

Yaklaşık 250k Dizüstü bilgisayarımda 6s.

Golfsiz kod yorumladı: http://jsfiddle.net/82xb9/3/ şimdi daha iyi sigma testi ve daha iyi bir durum ile (teşekkür ederim yorumlar)

Sürümleri önceden düzenleme: http://jsfiddle.net/82xb9/ http://jsfiddle.net/82xb9/1/


Sorusu (JS fiilleri yoktur) bir fonksiyonu veya program için sormak, bu nedenle oldukça ilk satırı hariç daha bir işlev bildiriminde ikinci çizgiyi sarın ve son değiştirmelisiniz k--;ile return k-1. O hafifçe bayt sayısını artırmakla birlikte değiştirmekte gibi şeyler ile birkaç kaydedebilirsiniz p[i]>=P+2ile p[i]>P+1(ve muhtemelen iç işlev çağrısını çıkarıp bir kullanarak breakyerine).
Peter Taylor

"Test sigma" kısmı hem boyut hem de hız için yeniden yazılabilir düşünüyorum: jsfiddle.net/3DTSa . Bu JS çözümü olduğu gibi çok hızlı olsa da.
user2846289
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.