Bölünebilir sayılar


47

OEIS'in Evrimi üzerinde çalışırken bu sırayı buldum , ancak hiçbir zaman bir cevap olarak bulamadım . Mathematica'da bir referans uygulaması yazdıktan sonra, bunun ayrı bir meydan okuma olarak yapmanın eğlenceli bir egzersiz olduğunu düşündüm, işte başlıyoruz.

Sayısal bir fisyon reaktörü inşa edelim! Olumlu bir tamsayı düşünün N. Örnek olarak, bakacağız 24. Bu sayıyı bölmek için, toplanacak en büyük ardışık pozitif tam sayı sayısını bulmak zorundayız N. Bu durumda, bu 7 + 8 + 9 = 24. Bu yüzden 24üç yeni sayıya bölündük . Fakat bu, zincir reaksiyonu olmayan bir fisyon reaktörü değildir. Öyleyse, bu bileşenler için işlemi tekrarlı olarak tekrarlayalım:

       24
       /|\
      / | \
     /  |  \
    7   8   9
   / \     /|\
  3   4   / | \
 / \     /  |  \
1   2   2   3   4
           / \
          1   2

Sayı, daha küçük ardışık tamsayılara ayrıştırılamadığında işlemi durdurduğumuza dikkat edin. Ayrıca yazılı olabilirdi unutmayın 9olarak 4 + 5, ancak 2 + 3 + 4daha fazla bileşen vardır. Bölünme sayısı arasında Nhemen da dahil olmak üzere bu işlem, elde edilen tam sayı sayısı olarak tanımlanır Nkendisini. Yukarıdaki ağacın 13 düğümü vardır, öyleyse F(24) = 13.

Bu dizi OEIS girişi A256504'tür .

İlk 40 terim, başlayarak N = 1,

1, 1, 3, 1, 5, 6, 5, 1, 6, 7, 12, 10, 12, 11, 12, 1, 8, 16, 14, 17, 18, 18,
23, 13, 21, 18, 22, 23, 24, 19, 14, 1, 22, 20, 23, 24, 31, 27, 25, 26

Bu pastebinde ilk 1000 terim bulunabilir .

Meydan okuma

Olumlu bir tamsayı verildiğinde N, Fisyon numarasını belirleyin F(N). (Yani 0, OEIS'te listelenen lideri örtmeniz gerekmez .)

STDIN (veya en yakın alternatif), komut satırı argümanı veya işlev argümanı yoluyla giriş alarak ve sonucu STDOUT (veya en yakın alternatif), fonksiyon dönüş değeri veya function (out) parametresi ile çıktı alarak bir program veya işlev yazabilirsiniz.

Bu kod golf, yani en kısa cevap (bayt cinsinden) kazanır.

Bonus sorusu: Bu dizinin ilginç özelliklerini bulabilir misiniz?


OEIS'in n = 34'te bir hataya sahip olduğunu fark ettim: n = 32'den başlayarak, (şu anda) 1, 22, 22, 23, 24, 31 yerine 1, 22, 20, 23, 24 numaralı listeleri listelediğini, 31.
mathmandan

1
@ mathmandan İyi yakalama, muhtemelen bir düzeltme önereceğim (ilk diyagramla birlikte).
Martin Ender


@ mathmandan FYI, diziyi ve örneği şimdi düzelttim ve referans uygulamamı ve ilk 10k terimlerini de ekledim.
Martin Ender

İyi görünüyor! Çalışmanız için teşekkürler!
mathmandan

Yanıtlar:


16

Pyth, 23 22 21 bayt

Lh&lJfqbsT.:tUb)syMeJ

Bu özyinelemeli bir işlevi tanımlar y. Çevrimiçi deneyin: Gösteri

Açıklama:

L                      define a function y(b): return ...
            tUb          the list [1, 2, ..., b-1]
          .:   )         generate all consecutive sub-sequences
     f                   filter for sub-sequences T, which satisfy:
      qbsT                   b == sum(T)
    J                    and store them in J

                         return 
   lJ                        len(J)
  &                        and (if len(J) == 0 then 0 else ...)
                    eJ       last element of J (=longest sub-sequence) 
                  yM         recursive calls for all these numbers
                 s           sum
 h                         incremented by one (counting the current node)

52

Fission , 1328 989 887 797 bayt

Bu cevap biraz uzun sürüyor ( keşfedilebilir bölgeleri olsaydı ) ... lütfen bunu geçmeyi ve diğer cevaplara biraz sevgi göstermeyi unutma!

Bu kod üzerinde çalışmak, bu zorluğa ilham veren şeydi. Fission'da EOEIS'e bir cevap eklemek istedim, bu da beni bu diziye götürdü. Ancak, aslında Fission öğrenmek ve bunu uygulamak birkaç hafta sürdü. Bu arada, dizilim gerçekten üzerimde büyümüştü, bu yüzden bunun için ayrı bir meydan okumaya karar verdim (artı, bu özellikle de EOEIS üzerindeki ağaca çok uzak olmazdı).

Bu yüzden size Monstrosity'yi sunuyorum:

 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
9\   ;    7A9
SQS  {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \  D /8/
~4X /A@[  %5                   /; &    K  } [S//~KSA /
  3    \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ { +X
W7           X  X    /> \      +\ A\ /   \ /6~@/ \/
        /   ~A\;     +;\      /@
    ZX [K    / {/  / @  @ }  \ X @
       \AS   </      \V /    }SZS S/
         X   ;;@\   /;X  /> \ ; X X
 ;       \@+  >/ }$S SZS\+;    //\V
           / \\  /\; X X @  @  \~K{
           \0X /     /~/V\V /   0W//
    \        Z      [K \  //\
W       /MJ $$\\ /\7\A  /;7/\/ /
       4}K~@\ &]    @\  3/\
 /     \{   }$A/1 2  }Y~K <\
[{/\  ;@\@  /   \@<+@^   1;}++@S68
@\ <\    2        ;   \    /
$  ;}++ +++++++L
%@A{/
M  \@+>/
~     @
SNR'0YK
  \  A!/

Girdide izleyen bir yeni satır olmadığını umuyor, bu yüzden onu aramak isteyebilirsiniz echo -n 120 | ./Fission oeis256504.fis.

Düzen muhtemelen daha verimli olabilirdi, bu yüzden hala iyileştirilmesi gereken çok yer var (örneğin, bu 911 581 461 374 boşluk içeriyor ).

Açıklamaya geçmeden önce, bunun test edildiğine dair bir not: resmi tercüman tamamen olduğu gibi çalışmaz. a) Mirror.cpppek çok sistemde derlenmez. Bu soruna rastlarsanız, rahatsız edici çizgiyi yorumlayın - etkilenen bileşen (rastgele bir ayna) bu kodda kullanılmaz. b) Tanımlanmamış davranışa yol açabilecek birkaç hata vardır (ve bu karmaşık bir program için muhtemelen olacaktır). Düzeltmek için bu düzeltme ekini uygulayabilirsiniz . Bunu yaptıktan sonra, tercümanı ile derleyebilmeniz gerekir.

g++ -g --std=c++11 *.cpp -o Fission

Eğlenceli gerçek: Bu program, Fisyon'un sunduğu #(rastgele aynalar), :(yarım aynalar) -veya |(düz aynalar) ve "(baskı modu) dışındaki neredeyse tüm bileşenlerini kullanır .

Peki ya dünya?

Uyarı: Bu çok uzun sürecek ... Fission'ın nasıl çalıştığı ve nasıl programlanabileceği ile gerçekten ilgilendiğinizi farz ediyorum. Çünkü eğer yapmazsan, bunu nasıl özetleyebileceğimden emin değilim. (Bir sonraki paragraf, dilin genel bir tanımını verir.)

Fisyon, hem veri hem de kontrol akışının bir ızgara boyunca hareket eden atomlarla temsil edildiği iki boyutlu bir programlama dilidir . Eğer Marbelous'u daha önce gördüyseniz veya kullandıysanız , konsept belli belirsiz olmalıdır. Her atomun iki tamsayılı özelliği vardır: negatif olmayan bir kütle ve isteğe bağlı bir enerji. Kütle hiç negatif olursa, atom ızgaradan çıkarılır. Çoğu durumda kütleyi atomun "değeri" olarak değerlendirebilir ve enerjiyi, atomların akışını belirlemek için çeşitli bileşenler tarafından kullanılan bir çeşit meta-özellik olarak değerlendirebilirsiniz (yani çoğu anahtar türü işaretine bağlıdır). Enerji). (m,E)Gerektiğinde atomları belirteceğim . Programın başında, ızgara bir demet ile başlar.(1,0)dört bileşenin üzerine yerleştirdiğiniz her yerden atom UDLR(buradaki harf, atomun başlangıçta hareket ettiği yönü gösterir). Tahta daha sonra atomların kütlesini ve enerjisini değiştiren, yönlerini değiştiren veya daha sofistike şeyler yapan bir dizi bileşenle doldurulur . Tam bir liste için esolangs sayfasına bakın , ancak çoğunu bu açıklamada açıklayacağım. Programın birkaç kez kullandığı bir diğer önemli nokta, ağın toroidal olmasıdır: Tarafların herhangi birine çarpan, aynı yönde hareket eden, herhangi bir tarafa çarpan bir atom.

Programı birkaç daha küçük parçaya yazdım ve sonunda birleştirdim, bu yüzden açıklamaya devam edeceğim.

atoi

Bu bileşen ilgi çekici görünmeyebilir, ancak hoş ve basit ve Fission'in aritmetiği ve kontrol akışı ile ilgili önemli kavramları tanıtmama izin veriyor. Bu nedenle, bu bölümden oldukça titiz bir ayrıntıyla geçeceğim, böylece diğer parçaları yeni Fission mekaniği tanıtmaya indirgeyebilir ve detaylı kontrol akışını takip edebilmeniz gereken üst seviye bileşenleri işaret edebilirim.

Fisyon, sayıların tamamını değil, yalnızca tek tek karakterlerden bayt değerlerini okuyabilir. Bu kabul edilebilir bir uygulama olsa da , ben varken, doğru yapabilirim ve gerçek tamsayıları STDIN üzerinde çözümleyebilirim. İşte atoikod:

     ;
 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J 
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
           O

Fisyondaki en önemli bileşenlerden ikisi fisyon ve füzyon reaktörleridir. Fisyon reaktörlerinden herhangi biri V^<>(yukarıdaki kodun kullandığı <ve >). Bir fisyon reaktörü, bir atomu (karakterin kamasına göndererek), varsayılanı saklayabilir (2,0). Bir atom karakterin tepesine çarparsa, iki yeni atom kenarlara gönderilir. Kütleleri, gelen kütlenin depolanan kütle ile bölünmesiyle belirlenir (yani varsayılan olarak yarıya iner) - soldaki atom bu değeri alır ve sağdaki atom kütlenin kalanını alır (yani kütle fisyonda korunur) . Her iki giden atom da gelen enerji eksi değerine sahip olacaktır.depolanan enerji. Bu, aritmetik için fisyon reaktörlerini kullanabileceğimiz anlamına gelir - hem çıkarma hem de bölme için. Bir fisyon reaktörü bölgeden vurulursa, atom basitçe çapraz olarak yansıtılır ve sonra karakterin tepe yönünde hareket eder.

Füzyon reaktörlerinden herhangi biri YA{}(yukarıdaki kodun kullandığı Yve {). İşlevleri benzer: bir atom depolayabilirler (varsayılan (1,0)) ve apeksten vurulduğunda iki yeni atom yanlara gönderilir. Bununla birlikte, bu durumda iki atom aynı olacaktır, her zaman gelen enerjiyi korur ve gelen kütleyi depolanan kütle ile çarpın. Yani, varsayılan olarak, füzyon reaktörü sadece tepesine çarpan herhangi bir atomu kopyalar. Yanlardan vurulduğunda, füzyon reaktörleri biraz daha karmaşıktır: Atom ayrıcaBir atom diğer tarafa çarpıncaya kadar (diğer bellekten bağımsız olarak) depolanır. Bu olduğunda, kütlesi ve enerjisi iki eski atomun toplamı olan tepe yönünde yeni bir atom serbest bırakılır. Eşleşen bir atom karşı tarafa ulaşmadan önce yeni bir atom aynı tarafa vurursa, eski atomun üzerine yazılır. Ekleme ve çarpma işlemlerini gerçekleştirmek için füzyon reaktörleri kullanılabilir.

Ben yolumdan almak istiyorum başka basit bileşenidir [ve ]hangi basitçe sağa atomun yönünü ayarlamak ve (ne olursa olsun, gelen yönü) sırasıyla, sol. Dikey eşdeğerler M(aşağı) ve W(yukarı) olmakla birlikte, atoikod için kullanılmazlar . UDLRayrıca WM][ilk atomlarını serbest bıraktıktan sonra da etki ederler.

Neyse, oradaki koda bakalım. Program 5 atomla başlar:

  • RVe Laltta sadece ile (kütle artışı elde +) olmak (10,0)ve daha sonra, sırasıyla bir fizyon ve bir füzyon reaktöründe saklanır. Temel 10 girişini ayrıştırmak için bu reaktörleri kullanacağız.
  • LSağ üst köşede kütlesi (düşülmesi alır _olmak için) (0,0)ve bir füzyon reaktöründe yan depolanır Y. Bu okuduğumuz sayının kaydını tutmak içindir - sayıları okudukça kademeli olarak arttırıp çoğaltacağız.
  • RÜst sol köşede karakteri yasasında yapılacak kitlesel setini alır 0ile (48) '0daha sonra kütle ve enerji ile takas edilir @ve son olarak kitle ile bir kez artış +vermek (1,48). Daha sonra, çapraz aynalarla yönlendirilir \ve /bir fisyon reaktöründe depolanır. 48ASCII girişini basamakların gerçek değerlerine dönüştürmek için for çıkarma'yı kullanacağız . Ayrıca 1bölünmeyi engellemek için kütleyi artırmak zorunda kaldık 0.
  • Son olarak, Usol alt köşedeki aslında her şeyi harekete geçiren şeydir ve başlangıçta yalnızca kontrol akışı için kullanılır.

Sağa yönlendirildikten sonra, kontrol atomu vurur ?. Bu giriş bileşenidir. Bir karakter okur ve atomun kütlesini okunan ASCII değerine ve enerjiye ayarlar 0. Bunun yerine EOF'ye çarparsak, enerji ayarlanacaktır 1.

Atom devam eder ve sonra vurur %. Bu bir ayna anahtarı. Pozitif olmayan enerji için bu bir /ayna gibi davranır . Ancak pozitif enerji için bir gibi davranır \(ve aynı zamanda enerjiyi 1 oranında azaltır). Böylece karakterleri okurken, atom yukarı doğru yansır ve karakteri işleyebiliriz. Ancak girdiyle işimiz bittiğinde, atom aşağıya doğru yansıyacak ve sonucu almak için farklı bir mantık uygulayabiliriz. Bilginize, karşıt bileşen &.

Şimdilik hareket eden bir atomumuz var. Her karakter için yapmak istediğimiz rakam değerini okumak, bunu toplam toplamımıza eklemek ve daha sonra bir sonraki haneye hazırlanmak için toplam 10'la çarpmak.

Karakter atomu önce (varsayılan) bir füzyon reaktörüne isabet eder Y. Bu, atomu böler ve soldaki kopyayı giriş bileşenine geri dönüp bir sonraki karakteri okumak için kontrol atomu olarak kullanırız. Doğru olan kopya işlenecek. Karakteri okuduğumuz durumu düşünün 3. Atomumuz olacak (51,0). Kütle ve enerjiyi değiştiririz @, böylece bir sonraki fisyon reaktörünün çıkarılmasını kullanabiliriz. Reaktör 48enerjiyi çıkarır (kütleyi değiştirmeden), bu yüzden iki kopyasını gönderir (0,3)- enerji şimdi okuduğumuz rakama karşılık gelir. Devam eden kopya basitçe atılır ;(gelen tüm atomları sadece yok eden bir bileşen). Devam eden kopya ile çalışmaya devam edeceğiz. Yolunu yol boyunca izlemeniz gerekir/ve \biraz aynalar.

@Sadece tekrar füzyon reaktör takasları kütle ve enerji önce, ekleyeceğiz şekilde (3,0)bizim değişen toplama Y. Bu nedenle toplam çalışmanın kendisinin daima 0enerjisine sahip olacağını unutmayın .

Şimdi Jbir sıçrama. Yaptığı herhangi bir atomu enerjisiyle ileriye atlamak. Eğer öyleyse 0, atom sadece düz devam ediyor. Eğer 1bir hücreyi 2atlayacaksa, iki hücreyi atlayacak ve böyle devam edecektir . Enerji atlamada harcanır, böylece atom daima enerji ile sona erer 0. Akan toplamın sıfır enerjisi olduğundan, atlama şimdilik göz ardı edilir ve atom, {kütlesini çarparak füzyon reaktörüne yönlendirilir 10. Devam eden kopya, yeni çalışan toplam olarak reaktöre ;geri beslenirken aşağıya doğru kopya atılır Y.

Yukarıdakiler, EOF'ye ulaşana kadar (öncekiler yapılmadan önce yeni rakamların işlendiği komik bir boru hattı şeklinde) tekrarlamaya devam ediyor. Şimdi %atom atomu aşağı doğru gönderecek. Fikir, (0,1)çalışan toplam reaktöre çarpmadan önce bu atomu şimdiye çevirmektir , böylece a) toplam etkilenmez (sıfır kütle) ve b) 1üstünden atlamak için bir enerji elde ederiz [. Enerjiyi $artıran enerjiyle kolayca ilgilenebiliriz .

Mesele şu ki ?, EOF'a çarptığınızda kütleyi sıfırlamamaktadır, bu yüzden kütle hala en son okunan karakter olacaktır ve enerji olacaktır 0(çünkü geri %çekilmiştir ). Bu yüzden o kütleden kurtulmak istiyoruz. Bunu yapmak için tekrar kütle ve enerjiyi değiştiriyoruz .10@

Ben bu bölümü bitiriyor önce bir daha bileşeni uygulamaya koyması gerekmektedir: Z. Bu aslında %veya ile aynıdır &. Aradaki fark, pozitif enerji atomlarının doğrudan enerjiden geçmesine izin vermesidir (enerjiyi azaltırken) ve pozitif enerji içermeyen atomları 90 derece sola saptırmasıdır. Bunu, bir atomun enerjisini, Ztekrar tekrar ve içinden geçirerek elimine etmek için kullanabiliriz - enerji biter bitmez, atom saptırılır ve döngüyü terk eder. Bu şudur:

/ \
[Z/

enerji sıfır olduğunda atomun yukarı doğru hareket edeceği yer. Bu deseni programın diğer bölümlerinde bir şekilde veya birkaç kez kullanacağım.

Atomu bu küçük döngü bırakır Bu yüzden, bunun olacak (1,0)ve takas (0,1)ile @giriş nihai sonucu serbest bırakmak için füzyon reaktörü isabet önce. Bununla birlikte, toplam çalışma 10'luk bir oranla kapalı olacaktır, çünkü zaten geçici olarak başka bir rakam için çarptık.

Şimdi enerji ile 1, bu atom atlayacak [ve içine atlayacaktır /. Bu, onu 10'a bölmek ve yabancı çarpımımızı düzeltmek için hazırladığımız bir fisyon reaktörüne saptırıyor. Yine, yarısını atar ;ve diğerini çıktı olarak tutarız (burada Okarşılık gelen karakteri basar ve atomu yok eder - burada tam programda atomu kullanıyoruz).

itoa

           /     \
input ->  [{/\  ;@
          @\ <\   
          $  ;}++ +++++++L
          %@A{/
          M  \@+>/
          ~     @
          SNR'0YK
            \  A!/

Tabii ki, sonucu tekrar bir dizgeye dönüştürmek ve yazdırmak zorundayız. Bu kısım bunun için var. Bu, girişin 10 ya da öylesine önce gelmediğini, ancak tam programda kolayca verildiğini varsayar. Bu bit tam programın altında bulunabilir.

Bu kod yeni ve çok güçlü bir Fission bileşeni sunar: yığın K. Yığın başlangıçta boştur. Negatif olmayan enerjili bir atom yığına çarptığında, atom basitçe yığının üzerine itilir. Negatif enerjili bir atom yığına çarptığında, kütlesi ve enerjisi yığının tepesindeki atom tarafından değiştirilir (bu şekilde atılır). Yığın boş olsa da, atomun yönü tersine çevrilir ve enerjisi pozitif olur (yani çarpılır -1).

Tamam, asıl koda dönelim. itoaSnippet'in fikri, bir sonraki yinelemede girişi 10'a bölerken bir sonraki haneyi bulmak için giriş modülünü 10 tekrar tekrar almaktır. Bu, tüm basamakları ters sırayla verir (en az anlamlıdan en anlamlıya). Siparişi düzeltmek için, tüm rakamları bir yığına iteriz ve sonunda bunları yazdırmak için birer birer açılır.

Kodun üst yarısı rakam hesaplamasını yapar: Lartılarla birlikte 10'a bir fizyon ve füzyon reaktörüne klonladığımız ve beslediğimiz bir 10 verir, böylelikle 10 ile çarpabilir ve çarpabiliriz. Döngü esasen [sol üst köşeden sonra başlar . Mevcut değer bölünür: bir kopya 10'a bölünür, daha sonra 10'la çarpılır ve bir fisyon reaktöründe saklanır, daha sonra tepedeki diğer kopyaya çarpılır. Bu hesaplar i % 10olarak i - ((i/10) * 10). Ayrıca A, ara sonucu bölme işleminden sonra ve çarpmadan önce i / 10bölerek bir sonraki yinelemeye besleyebileceğimizi unutmayın .

%Çünkü bu yineleme değişkeni 0 değerini tatmin edecek bir kez döngü iptal veya daha az bir do-süre döngü, bu kod olur baskı için bile çalışma 0(öncü sıfır, aksi yaratmadan). Döngüyü terk ettikten sonra yığını boşaltmak ve rakamları yazdırmak istiyoruz. Stersi olduğundan Z, gelen bir atomu pozitif olmayan enerjiyle sağa doğru 90 derece sapacak bir anahtardır. Gelen kenar üzerinde atomu aslında hareket Böylece Sdüz Kbir basamak kapalı pop (not ~gelen atomu enerjisine sahip olduğunu olan sağlar -1). Bu rakam, 48karşılık gelen rakam karakterinin ASCII kodunu almak için artırılır . Aİle bir kopya yazdırmak için haneyi böler!ve diğer kopyayı bir Ysonraki basamak için reaktöre geri besleyin . Yazdırılan kopya, yığın için bir sonraki tetikleyici olarak kullanılır (aynaların M, soldan vurmak için kenarın çevresine de gönderdiğini unutmayın ).

Yığın boşaldığında, Kirade atomu yansıtacak ve enerjisini +1doğrudan içinden geçecek şekilde dönüştürecektir S. Nyeni bir satır yazdırır (sadece düzgün olduğu için :)). Ve sonra atom R'0, tarafına gelecek şekilde tekrar üzerinden gider Y. Çevresinde daha fazla atom olmadığından, bu asla serbest bırakılmayacak ve program sona erecektir.

Fisyon Numarasını Hesaplamak: Çerçeve

Programın asıl etine gidelim. Kod, temelde Mathematica referans uygulamamın bir limanıdır:

fission[n_] := If[
  (div = 
    SelectFirst[
      Reverse@Divisors[2 n], 
      (OddQ@# == IntegerQ[n/#] 
       && n/# > (# - 1)/2) &
    ]
  ) == 1,
  1,
  1 + Total[fission /@ (Range@div + n/div - (div + 1)/2)]
]

nerede divmaksimal bölümünde tamsayılar sayısıdır.

Başlıca farklar, Fission'ta yarı-tamsayı değerleriyle baş edemememizdir, bu yüzden iki ile çarpılan birçok şey yapıyorum ve Fission'ta tekrarlama yok. Bu soruna geçici bir çözüm bulmak için, bir bölümdeki tüm tamsayıları daha sonra işlenecek bir kuyrukta zorluyorum. İşlediğimiz her sayı için bir sayacı birer birer artırırız ve sıra boşalınca sayacı serbest bırakır ve yazdırılması için göndeririz. (Bir sıra, FIFO sırasına göre Qtam olarak aynı şekilde çalışır K.)

İşte bu kavram için bir çerçeve:

                      +--- input goes in here
                      v 

                     SQS ---> compute div from n          D /8/
                     ~4X               |                /~KSA /
                       3               +----------->    { +X
initial trigger ---> W                               6~@/ \/
                              4                   
                     W        ^                     /
                              |              3
                     ^     generate range    |
                     |     from n and div  <-+----- S6
                     |         -then-      
                     +---- release new trigger

En önemli yeni bileşenler rakamlardır. Bunlar teleporterler. Aynı sayıdaki tüm telekomünikasyon şirketleri birbirine aittir. Bir atom herhangi teleporter çarptığında hemen olmak aynı grupta, sonraki teleporter hareket edecek yanındaki tepeden aşağıya doğru sıralanmıştır, her zamanki soldan sağa belirlenir. Bunlar gerekli değildir, ancak yerleşim düzenine yardımcı olurlar (ve dolayısıyla biraz golf oynarlar). Ayrıca Xbir atomu çoğaltan, bir kopyasını dümdüz ileri geri diğeri gönderen de var.

Şimdiye dek çerçevenin çoğunu kendiniz çözebilirsiniz. Sol üst köşede hala işlenecek değerler kuyruğu vardır ve birer birer serbest bırakır n. Bir kopyası nalt tarafa gönderilir, çünkü aralığı hesaplarken ihtiyacımız vardır, diğer kopya ise hesaplayan üstteki bloğa girer div(bu kodun en büyük kısmıdır). Bir kez divhesaplandıktan sonra kopyalanır - bir kopya, sağ üst köşede bulunan bir sayacı arttırır K. Diğer kopya alt tarafa gönderilir. Olursa div, 1derhal yukarı doğru saptırır ve herhangi bir yeni değer belirtmeden, bir sonraki yineleme için tetikleyici olarak kullanırız. Aksi takdirde kullandığımız divven alt kısımdaki bölümde yeni aralığı (yani, sıraya konan karşılık gelen kütlelere sahip bir atom akışı) üretin ve ardından aralık tamamlandıktan sonra yeni bir tetikleyici serbest bırakın.

Kuyruk boşaldığında, tetikleyici doğrudan içinden geçerek Sve sağ üst köşede yeniden beliren şekilde yansıtılır, burada sayacı (son sonucu) Abırakıp, sonradan itoaüzerinden iletilir 8.

Fisyon Sayısının Hesaplanması: Döngü Gövdesi

Yani geriye kalan tek şey div, aralığı hesaplayan ve üreten iki bölümdür . Hesaplama divbu kısım:

 ;    
 {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \
/A@[  %5                   /; &    K  } [S/
   \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ 
         X  X    /> \      +\ A\ /   \ /
    /   ~A\;     +;\      /@
ZX [K    / {/  / @  @ }  \ X @
   \AS   </      \V /    }SZS S/
     X   ;;@\   /;X  /> \ ; X X
     \@+  >/ }$S SZS\+;    //\V
       / \\  /\; X X @  @  \~K{
       \0X /     /~/V\V /   0W//
\        Z      [K \  //\
           \ /\7\A  /;7/\/

Muhtemelen şimdi biraz sabırla kendin için bunu çözecek kadar gördün. Üst düzey dağılım şudur: İlk 12 sütun ya da öylesine bir bölenler akışı oluşturur 2n. Sonraki 10 sütun tatmin etmeyenleri filtrelemektedir OddQ@# == IntegerQ[n/#]. Sonraki 8 sütun tatmin etmeyenleri filtreliyor n/# > (# - 1)/2). Sonunda, tüm geçerli bölenleri bir yığına iteriz ve bir kez yaptığımızda, tüm yığını bir füzyon reaktörüne boşaltırız (son / en büyük bölenin üzerine yazar) ve sonucu serbest bırakırız, ardından enerjisini ortadan kaldırırız (ki bu - eşitsizliği kontrol etmekten sıfır).

Gerçekten hiçbir şey yapmayan bir sürü çılgın yol var. Ağırlıklı olarak, \/\/\/\/tepedeki delilik ( 5s aynı zamanda bunun bir parçasıdır) ve tabanın etrafındaki bir yol ( 7s içinden geçer ). Bazı zorlu yarış koşullarıyla başa çıkmak için bunları eklemek zorunda kaldım. Fisyon bir gecikme bileşeni kullanabilir ...

Yeni aralığı üreten kod şudur nve divşudur:

 /MJ $$\
4}K~@\ &]    @\  3/\
\{   }$A/1 2  }Y~K <\
 \@  /   \@<+@^   1;}++@
  2        ;   \    /

İlk önce hesaplıyoruz n/div - (div + 1)/2(her iki terim de aynı sonucu veriyor) ve daha sonra saklıyoruz. Sonra divaşağıdan bir aralık oluştururuz 1ve saklanan değeri her birine ekleriz.

Biri şudur: iki yeni ortak Bunların ikisi de desenler, ben söz gerektiğini vardır SXya ZXaltına (veya döndürülmüş sürümleri) dan isabet. Bu, bir kopyanın doğrudan ilerlemesini istiyorsanız (bir füzyon reaktörünün çıkışlarını yönlendirmek bazen hantal olabilir), bir atomu kopyalamanın güzel bir yoludur. SYa da Zdöner içine atomu Xve daha sonra yayılma orijinal yönde yansıtılan kopya geri döner.

Diğer desen

[K
\A --> output

Eğer herhangi bir değeri Ksaklarsak K, üstten negatif enerji ile vurarak tekrar tekrar alabiliriz . ABizim ilgilendiğimiz değerini kopyalar ve ona ihtiyacımız sonraki sefer için yığının üzerine doğru geri kopyalamak neyi gönderir.

Eh, bu oldukça zorluydu ... ama bunu gerçekten yaşarsan, umarım Fission i͝s̢̘̗̗ ͢i̟nç̮̩r̸̭̬̱͔e̟̹̟̜͟d̙i̠͙͎̖͓̯b̘̠͎̭̰̼l̶̪̙̮̥̮y̠̠͎̺͜ ͚̬̮f̟͞u̱̦̰͍n͍ ̜̠̙t̸̳̩̝o ̫͉̙͠p̯̱̭͙̜͙͞ŕ̮͓̜o̢̙̣̭g̩̼̣̝r̤͍͔̘̟ͅa̪̜͇m̳̭͔̤̞ͅ ̜̠̙i͜n̳̯̗̳͇̹.̫̞̲̞̜̳ olduğunu biliyorsundur.


1
Now with 100% fewer scrollbars.Yani diyebiliriz .. ve onun hala Devam edecek ...
Doktoru

13
Genç geliştiricilerimizin çıkardığı birçok koddan daha okunaklı.
corsiKa

Fission'ın yaratıcısı olarak, ben bile o kadar büyük bir program yazmadım! Etkilendim! Açıklamanız muhteşem ve kesinlikle dil için bir rehber niteliğinde olabilir.
C0deH4cker

Ayrıca, cevabınızın son satırı bir Fission programına benziyor;)
C0deH4cker

12

CJam, 42 41 bayt

ri]{_{:X,:)_few:+W%{1bX=}=}%{,(},e_}h]e_,

Basit bir Genişlik ilk geçişi ve boş sonraki seviyenin durma koşulu.

Nasıl çalışır :

ri]                                       e# This represents the root of the fissile tree
   {                               }h     e# Now we run a do-while loop
    _{                    }%              e# Copy the nodes at the current level and map them
                                          e# via this code block to get next level nodes
      :X,:)                               e# Store the node value in X and get array [1..X]
           _few                           e# Copy the array and get continuous slices of
                                          e# length 1 through X from the array [1..X]
               :+W%                       e# Right now, we have an array of array with each
                                          e# array containing slice of same length. We join
                                          e# those arrays and reverse them to get slices of
                                          e# higher length in front of lower lengths
                   {1bX=}=                e# Choose the first slice whose sum is same as X
                                          e# The reversal above makes sure that we give
                                          e# preference to slice of higher length in case of
                                          e# multiple slices add up to X
                            {,(},         e# Filter out slices of length 1 which basically
                                          e# mean that the current node cannot be split up
                                 e_       e# Join all slices in a single array. This is our
                                          e# next level in the Fissile tree. If this is empty
                                          e# it means that all no further node can be
                                          e# decomposed. In an {}h do-while loop, this fact
                                          e# itself becomes the stopping condition for the
                                          e# loop
                                     ]e_, e# Wrap all levels in an array. Flatten the array
                                          e# and take its length

Burada çevrimiçi deneyin


Bu muhtemelen yaklaşık 35 bayta kadar golf yapılabilir. Nasıl olduğunu anlamaya çalışıyorum ..
Doktoru

10

Python 3, 112 bayt

def f(n,c=0):
 d=n-c;s=(n-d*~-d/2)/d
 return(s%1or s<1)and f(n,c+1)or+(d<2)or-~sum(f(int(s)+i)for i in range(d))

@FryAmTheEggman sayesinde 4 bayt kurtarıldı.

Açıklama daha sonra gelecek ...

Bonus gerçeği: 2'nin her gücünün 1 sayı değeri vardır. Bunun nedeni, düzgün uzunluk dizisinin toplamının her zaman, tam sayı olan dizinin uzunluğunun yarısı ile çarpılan tuhaf olan iki orta sayının toplamı olmasıdır. . Bir tek uzunluk dizisinin toplamı, tek sayı olan dizi uzunluğu ile çarpılan orta sayıdır. Dolayısıyla, 2'nin gücünün garip bir bölen olmadığı için, yalnızca kendi toplamı olarak ifade edilebilir.


2 + 3 + 4 + 5 = 14, tuhaf değil. Çift uzunluk dizileri için argümanınız "bir çift uzunluk dizisinin toplamı, uzun olanın yarısı ile çarpılan tek, orta sayıların toplamıdır" olarak değiştirilmelidir. İfadenin geri kalanı etkilenmeden geçer.
Bruno Le Floch

@BrunoLeFloch Teşekkürler! Düzeltildi.
randomra

Başlığınız gelişmeleri yansıtmıyor mu? yani <strike> 117 </strike> <strike> 113 </strike> 112
corsiKa

@corsiKa Genellikle sadece büyük gelişmeler için yapıyorum. Aksi taktirde çok fazla çarpılmış sayı olacaktır.
randomra

8

Python 2, 111 102 97 bayt

Biraz okunabilir:

def f(n,c=0):a=n-c;b=n-a*~-a/2;return 1/a or-~sum(map(f,range(b/a,b/a+a)))if b>b%a<1else f(n,c+1)

Çok da okunabilir değil:

def f(n,a=0):b=n-a*~-a/2;return b>0and(f(n,a+1)or b%a<1and(1/a or-~sum(map(f,range(b/a,b/a+a)))))

Her ikisi de 97 bayt.

bolduğu neksi (a-1)thüçgen sayısı. Eğer b % a == 0öyleyse n, aondan başlayarak ardışık sayıların toplamıdır b.


8
PPCG'ye katılmadan önce Python'u genel olarak okunabilir bir dil olarak görürdüm.
Alex A.

Okunabilir tanımınızı geliştirmeniz gerektiğini düşünüyorum.: P
Doktoru

Python 2 izin vermiyor 1else. Sadece 2. çözüm işe yarıyor. Python 3 elsehemen bir sayı takip edebilecek kadar değil .
mbomb007

@ mbomb007 Bildiğim kadarıyla, 2.7.8'den başlayarak iyi çalışıyor
Sp3000

Tamam, 2.7.2 kullanıyordum.
mbomb007

7

Python 2, 86

f=lambda n,R={1}:n-sum(R)and f(n,R^{[min(R),max(R)+1][n>sum(R)]})or-~sum(map(f,R-{n}))

Daha az golf oynadı:

def f(n,R={1}):
    d=sum(R)-n
    if d==0:return (sum(map(f,R-{n}))
    if d<0:return f(n,R|{max(R)+1})
    if d>0:return f(n,R-{min(R)})

Buradaki fikir, toplanacak ardışık tam sayıların potansiyel çalışmalarını test etmektir n. Koşu, Rbitiş noktaları yerine doğrudan bir küme olarak doğrudan depolanır .

Mevcut çalışmanın toplamının n, farkları üzerinden istenen toplamla karşılaştırmasını kontrol ederiz .

  • Toplam çok büyükse, çalışmadaki en küçük elemanı keseriz.
  • Toplam çok küçükse, çalışmayı maksimuma 1 oranında artırarak uzatırız.
  • fToplama doğruysa, yinelenir, koşuya eşlenir, toplar ve geçerli düğüm için 1 ekleriz. Eğer {n}öyleyse, önemsiz tüm olası toplamları denedik, nilk önce kaldırarak özyinelemeyi durdurun .

3 karakter kaydettiğiniz için Sp3000'e teşekkürler.


7

Python 2, 85

Bu cevapla gurur duyuyorum çünkü n = 9 için onlarca saniye, n = 10 için 5-10 dakika alıyor. Kod golfünde bu, bir programın istenen bir özelliği olarak kabul edilir.

f=lambda n,a=1,d=1:a/n or[f(a)+f(n-a,1+1%d*a)+1/d,f(n,a+d/n,d%n+1)][2*n!=-~d*(2*a+d)]

Ayrıca çok uzun sürmeyen ve aynı miktarda bayt kullanan kısa devre yapan bir sürümü de var:

f=lambda n,a=1,d=1:a/n or~d*(2*a+d)+n*2and f(n,a+d/n,d%n+1)or f(a)+f(n-a,1+1%d*a)+1/d 

Daha hızlı olabilir, ancak en azından n 40 değerinin biraz üstüne çıktığında varsayılan yineleme sınırını aşıyor.

Buradaki fikir sayıları ave dböyle bir a + a+1 + ... + a+d == ndeğeri 1 ile arasındaki değerlerde kaba kuvvet araması yapmaktır n. f(n,a+d/n,d%n+1)Yineleme dalı döngüsü (a, d)çiftleri. Eşitliğin sağlanması durumunda map(range(...)), dizilimin ne kadar uzun olduğuna bakılmaksızın sadece iki kollara bölerek pahalı bir çağrıdan kaçınmayı başardım . Sayılar a+1aracılığıyla dbir çağrı içine lumped fayarlayarak adiziyi bölmek için farklı bir yol kullanılamaz böylece parametre.


Bu nasıl çalışıyor?
xnor

"Bu cevapla gurur duyuyorum çünkü n = 9 için onlarca saniye, n = 10 için 5-10 dakika sürüyor. Golf kodunda bu, bir programın istenen bir özelliği olarak kabul ediliyor." Sadece bunun için + 1'ledi.
Soham Chowdhury

6

Haskell, 76 69 bayt

f x=head$[1+sum(map f[y..z])|y<-[1..x-1],z<-[y..x],sum[y..z]==x]++[1]

Kullanımı:

*Main> map f [1..40]
[1,1,3,1,5,6,5,1,6,7,12,10,12,11,12,1,8,16,14,17,18,18,23,13,21,18,22,23,24,19,14,1,22,20,23,24,31,27,25,26]

Nasıl çalışır:

[  [y..z] |y<-[1..x-1],z<-[y..x],sum[y..z]==x]

           make a list of lists with all consecutive integers (at least 2 elements)
           that sum up to x, sorted by lowest number, e.g. 9 -> [[2,3,4],[4,5]].

1+sum(map f[...]) 

           recursively calculate the Fission Number for each list

[...]++[1]

           always append the 1 to the list of Fission Numbers.

head

           take the first element, which is either the Fission Number of the
           longest list or if there's no list, the 1 appended in the step before.  

3

Retina , 66 bayt

^|$
,
(`,(1+?)(?=(?<1>1\1)+\D)
$0;
+)`,(1*);1\1
,$1,1$1;
^,|1

.
1

Girdiyi alır ve çıktıları aynı anda yazdırır.

Her satırı tek bir dosyaya koyabilir veya kodu -sbayrakta olduğu gibi çalıştırabilirsiniz . Örneğin:

> echo -n 1111111|retina -s fission
11111

Açıklama:

  • Bölünecek sayıların virgülle ayrılmış bir listesini tutarız.
  • Her sayı için geçerli bir ayrıştırma oluşturabilen ve geri kalanından noktalı virgülle sınırlandırabilen en küçük başlangıç ​​değerini alırız.
  • Bir sayının içinde noktalı virgül varsa onu virgül olarak değiştiririz ve sayının bir sonraki düzgün boyutta (önceki öğenin uzunluğu + 1) kısmını sınırlar.
  • Değişiklikler gerçekleşene kadar 2. ve 3. adımları tekrar ediyoruz.
  • Her yaprak için virgül ve her iç düğüm için noktalı virgül ve ek virgül alıyoruz çünkü iki virgül ile başladık. Bu yüzden virgül ve sayıları 'parçaları 1' çıkarırız ve gerisini 1's' e dönüştürürüz .

Girdi ile işlem boyunca dizenin durumları 11111111111111 (unary 14):

,11111111111111,
,11;111111111111,
,11,1;11,1111,11;111;,
,11,1,11;,1111,11,1;11;;,
,11,1,11;,1111,11,1,11;;;,
,,;,,,,;;;,
11111111111

@MartinButtner sohbet için yardım için çok teşekkürler!


3

CJam (43 bayt)

qi,{):X),_m*{{_)*2/}/-X=}=~\,>0\{~$+}/)}%W=

Çevrimiçi demo

Gelişmiş döngülerle ilgili bazı ipuçlarını özlediğimden eminim, ancak bu, bir %harita içinde sonuçların yığında kalmasını ve dolayısıyla $bir negatif kayma.


Yarın daha yakından bakacağım, ama başlangıç ​​için başlangıçta ihtiyacın yok ,. /ve %birkaç diğer kişi ise dolaylı olarak sayıları aralıklara dönüştürür.
Martin Ender

,_m*ile değiştirilebilir 2m*. Aritmetik ilerleme formülü ile değiştirilebilir ~,>:Y_,+:+ve ~\,>0\ olur !Y. Son olarak, {}#yerine kullanırsanız {}=, )sonrasına ihtiyacınız yoktur X. Hepsini bir araya getirmek:ri{):X2m*{~,>:Y_,+:+X=}#!Y{~$+}/)}%W=
Dennis

2

Git, 133 bayt

func 算(n int)int{Σ:=1;for i:=0;i<n;i++{for j:=0;j<n;j++{if i*i+i-j*j-j==2*n{for k:=j+1;k<=i;k++{Σ+=算(k)};j,i=n,n}}};return Σ}

Bu benim ilk kod golf, eğer herhangi bir hata yaptıysam özür dilerim.

Bu, bölünebilir "kompozisyon" un iki sıralı tamsayı dizisi arasında bir fark olarak görülebileceği fikrini kullanır. Örneğin 13 sayısı için fissile "kompozisyon" al. Bu 6,7. Ancak 1 ... 7 tamsayılarının toplamı eksi 1 ... 5 tamsayılarının toplamı olarak görülebilir.

  A: 1 2 3 4 5 6 7  sum = 28
  B: 1 2 3 4 5      sum = 15 
A-B:           6 7  sum = 13, which is also 28-15 = 13

Gauss'un okul günlerindeki formülü hatırlayın, toplamı 1 ... n = (n ^ 2 + n) / 2. Böylece, belirli bir n için sıralı tamsayıların bir kompozisyonunu bulmak için şunu söyleyebiliriz ki, 1 ... n aralığında 'p ve q' noktalarını arıyoruz, böylece (p ^ 2 + p) / 2 - ( q ^ 2 + q) / 2 = n. Yukarıdaki örnekte, '5 ve 7' noktalarını arıyorduk çünkü 7 ^ 2 + 7 = 56/2, 5 ^ 2 + 5 = 30/2, 56 / 2-30 / 2 = 28-15 = 13.

Şimdi Martin'in 9 = 2 + 3 + 4 ve 4 + 5'in de belirttiği gibi, sayı oluşturmak için birden fazla olası yol var. Fakat "en düşük" başlangıç ​​sırasının da en uzun olacağı açık, çünkü daha fazla orta ölçekli sayılardan daha büyük bir sayıya kadar küçük sayılar. (Maalesef kanıtım yok)

Öyleyse, 9’un kompozisyonunu bulmak için, her bir q son nokta çifti,, p ve q’yu test edin, p ve q’yu ayrı ayrı 0 ila 9 arasında tekrarlayın ve p ^ p + p / 2 - q ^ 2 + q / 2 = 9. Veya, daha basit bir ifadeyle, yuvarlama bölme sorunlarını önlemek ve tüm matematiği tam sayılarda tutmak için denklemi 2 ile çarpın. O zaman p ve q 'yı arıyoruz (p ^ p + p) - (q ^ q + q) = 9 * 2. Bulduğumuz ilk eşleşme Fissile bileşimi bitiş noktaları olacaktır, çünkü belirtildiği gibi, en düşük sayı grubunun da en uzun olacağı ve düşükten yükseğe (0'dan 9'a kadar) arama yaptık. Bir eşleşme bulur bulmaz döngüden ayrılırız.

Şimdi özyinelemeli işlev verilen n için bu 'bölünmez bitiş noktalarını' p ve q bulur, ardından ağaçtaki p 'den q' ya kadar her bir 'çocuk' için kendisini hatırlar. 9 için 1 ve 4'ü bulur (20-2 = 18), ardından 2, 3 ve 4'te tekrar çağırır ve sonuçları toplar. 4 gibi sayılar için hiçbir zaman bir eşleşme bulamaz ve '1' değerini döndürür. Bu kısaltılabilir ama bu benim üçüncü gitme programım gibi ve özyinelemede uzman değilim.

Okuduğunuz için teşekkürler.


İyi iş! Ama neden Unicode fonksiyon / değişken isimleri. Bu gereksiz bayt maliyeti ve kesinlikle sadece normal bir mektup kullanmak olabilirdi?
Martin Ender

Nazik yorumunuz için teşekkürler. Ama kendime sordum, neden bayt yerine karakterleri saymıyorum :)
parlak değil

Çünkü buradaki varsayılan kurallar bunlar. :) Genellikle bayt saymamamız ve karakter kullanmamamızın nedeni, aksi halde bunun gerçekleşmesi , katılan tüm taraflar için biraz eğlenceli. ;) (Yani herhangi meydan yazar, söz konusu olan yerine bayt karakterlerin sayımını belirtmek için ücretsiz, ama özellikle etmedi).
Martin Ender

1

CJam, 40 35 33 bayt

ri{__,f-_few:+{1b1$=}=|{F}*}:F~],

@Optimizer few, 2 bayt kaydetti, önermek için teşekkür ederiz .

CJam tercümanında çevrimiçi olarak deneyin .

Nasıl çalışır

ri      e# Read an integer from STDIN.
{       e# Define function F(X):
  _     e# Push X.
  _,    e# Push [0 ... X-1].
  f-    e# Subract each from X. Pushes Y := [X ... 1].
  _few  e# Push all overlapping slices of Y of length in Y.
  :+    e# Consolidate the slices of different lenghts in a single array.
  {     e# Find the first slice S such that...
    1b  e#   the sum of its elements...
    1$= e#   equals X.
  }=    e#   Since Y is in descending order, the first matching slice is also the longest.
  |     e# Set union with [X]. This adds X to the beginning of the S if S != [X].
  {F}*  e# Execute F for each element of S except the first (X).
}:F     e#
~       e# Execute F for the input.
],      e# Count the integers on the stack.

İlk yarımı ikinci ri{_,:)_few:+W%{1b1$=}=|{F}*}:F~],
Optimize Edici

@ Seçenek: Güzel. Bu ek bir iyileştirme sağlar. Teşekkürler!
Dennis,
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.