Baloncukları Düzenlemek


26

Dikkat, math.stackexchange'te sorulan sorudan kopyalanan zorluk .

Son zamanlarda, baloncukları üfleme konusunda oldukça yetenek kazandım. İlk başta bu gibi kabarcıkları patlardım görüntü tanımını buraya girin

Ama sonra işler garipleşmeye başladı:

görüntü tanımını buraya girin

Bir süre sonra, oldukça garip baloncuklar esiyordum:

görüntü tanımını buraya girin

Yüzlerce, hatta belki binlerce baloncuğu patlattıktan sonra, alnım birdenbire şu soruyu kırdı: “Baloncuklar düşerse, onları kaç farklı şekilde düzenleyebilirsin? Örneğin, n = 1 ise, sadece 1 düzenleme vardır. N = 2 ise 2 düzenleme vardır. N = 3 ise 4 düzenleme vardır. N = 4 ise 9 düzenleme vardır.

İşte 4 baloncuklu 9 düzenleme:
görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin

Tüm bu muhteşem baloncukları üfledikten sonra, onların düzenlemelerini sayma zevkini sizinle paylaşmam gerektiğine karar verdim. Yani burada senin görevin:


Hedef

Bir programı, işlevi veya benzerlerini yazarak nbaloncukları düzenleme şeklinizi sayar .


Giriş

n, baloncukların sayısı. n> 0


Çıktı

Bu baloncukları düzenleyebileceğiniz yolların sayısı.


Kazanma Kriterleri

Kodunuzun etrafında bir balon patlatabilirsek çok iyi olurdu. Kodunuzu ne kadar küçük yaparsanız, o kadar kolay olacaktır. Bu yüzden en az sayıda bayt ile kod yapan kişi yarışmayı kazanacaktır.


Ekstra bilgi

OEIS


5
Baloncuklar kesişebilirse, açık bir problemdir , n = 4 için 173 çözüm .
orlp

@orlp Neyse ki, bu kabarcıklar kesişmiyor.
TheNumberOne

1
0geçerli bir girdi?
Martin Ender

@ KenY-N Evet. Altta zaten bir OEIS bağlantısı var
Roman Gräf

Hata! Aptal yorum zamanı sil ...
Ken YN,

Yanıtlar:


12

Python 2, 92 87 bayt

a=lambda n:n<2or sum((k%d<1)*d*a(d)*a(n-k)for k in range(1,n)for d in range(1,1+k))/~-n

Sade ingilizce: a(n)hesaplamak d*a(d)*a(n-k)için her bir küçük dtamsayıdaki her pozitif bölenin bölenini hesaplar , onlardan kküçük veya ona eşit n, bunları toplar ve böleriz n-1.

O (yerine Python 3 çalıştırmak, daha hızlı çalışmasını sağlamak için /birlikte //yukarıdaki işlevinde) ve memoize:

import functools
a = functools.lru_cache(None)(a)

Bunu yaparsanız a(50) = 425976989835141038353anında hesaplar .


Vay, bu harika. Ben farz lru_cache()işlevi memoizes?
Patrick Roberts

@PatrickRoberts Evet, genellikle işlev dekoratör olarak kullanılır, ancak bir işleve elle de uygulayabilirsiniz.
orlp

@PatrickRoberts İşte için dokümanlarlru_cache .
PM 2R,

Bu işlev döndürür Trueiçin n<2. Bunun için ok sanırım n=1Python beri, Truesayısal bağlamlarda 1'e değerlendirir, ama a(0)sen ile düzeltmek olabilir 0'a dönmelidir n<2 and n or sum...ama daha kompakt bir yol olabilir.
PM 2R,

Sanırım sıfır kabarcıkları düzenlemenin bir yolu olduğu tartışılabilir, ancak bu A000081 ile tutarlı değil. OTOH, sadece pozitif için çözmemiz gerekirse n, tekrarlayan çağrıları daha yükseklere etkilememesi nedeniyle bu köşe durumunu güvenle görmezden gelebiliriz n.
PM 2Ring,

10

GNU Prolog, 98 bayt

b(x,0,x).
b(T/H,N,H):-N#=A+B+1,b(H,A,_),b(T,B,J),H@>=J.
c(X,Y):-findall(A,b(A,X,_),L),length(L,Y).

Bu cevap Prolog'un en basit I / O formatları ile bile nasıl mücadele edebileceğinin harika bir örneğidir. Sorunu çözecek algoritmadan ziyade problemi tanımlayarak gerçek Prolog tarzında çalışır: yasal bir kabarcık düzenlemesi olarak neyin sayılacağını belirler, Prolog'a tüm bu kabarcık düzenlemelerini oluşturmasını ister ve sonra bunları sayar. Nesil 55 karakter alır (programın ilk iki satırı). Sayma ve G / Ç diğer 43'ü alır (üçüncü satır ve iki parçayı ayıran yeni satır). Bu, OP'nin dillerin G / Ç ile mücadele etmesine neden olmasını beklediği bir sorun değil! (Not: Stack Exchange'in sözdizimi vurgulaması, okumayı zorlaştırır, kolaylaştırmaz, bu yüzden kapattım).

açıklama

Aslında işe yaramayan benzer bir programın sözde kod sürümü ile başlayalım:

b(Bubbles,Count) if map(b,Bubbles,BubbleCounts)
                and sum(BubbleCounts,InteriorCount)
                and Count is InteriorCount + 1
                and is_sorted(Bubbles).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

Nasıl bçalıştığı oldukça açık olmalıdır : kabarcıkları sıralı listelerle temsil ediyoruz (eşit eşitlikli çoklu eşlemelerin eşit karşılaştırılmasına neden olan basit bir çoklu uygulama uygulamasıdır) ve tek bir kabarcığın []sayısı olan daha büyük bir kabarcığın sayısı 1'dir. İçindeki toplam kabarcık sayısı artı 1'e eşittir. 4 sayısı için bu program (işe yaradıysa) aşağıdaki listeleri oluşturur:

[[],[],[],[]]
[[],[],[[]]]
[[],[[],[]]]
[[],[[[]]]]
[[[]],[[]]]
[[[],[],[]]]
[[[],[[]]]]
[[[[],[]]]]
[[[[[]]]]]

Bu program birkaç nedenden dolayı cevap olarak uygun değildir, ancak en acil olan Prolog'un aslında bir mapöngörüsünün olmamasıdır (ve yazması çok fazla bayt alacaktır). Bunun yerine programı daha çok şöyle yazarız:

b([], 0).
b([Head|Tail],Count) if b(Head,HeadCount)
                    and b(Tail,TailCount)
                    and Count is HeadCount + TailCount + 1
                    and is_sorted([Head|Tail]).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

Buradaki diğer büyük problem, Prolog'un değerlendirme emrinin işe yaraması nedeniyle, çalıştırıldığında sonsuz bir döngüye girmesi. Bununla birlikte, sonsuz döngüyü programı biraz yeniden düzenleyerek çözebiliriz:

b([], 0).
b([Head|Tail],Count) if Count #= HeadCount + TailCount + 1
                    and b(Head,HeadCount)
                    and b(Tail,TailCount)
                    and is_sorted([Head|Tail]).
c(Count,NPossibilities) if listof(Bubbles,b(Bubbles,Count),List)
                       and length(List,NPossibilities).

Bu oldukça garip görünebilir - ne olduklarını bilmeden önce sayıları bir araya getiriyoruz - ama GNU Prolog #=bu tür nedensel olmayan aritmetiği kullanabiliyor ve çünkü her şeyden önce bgelen HeadCountve TailCounther ikisi de daha küçük olmalı Count(ki bu bilinir), özyinelemeli terimin kaç kez eşleşebileceğini doğal olarak sınırlandırma yöntemi olarak hizmet eder ve bu nedenle programın daima sonlandırılmasına neden olur.

Bir sonraki adım, bu biraz aşağı golf oynamak. Gibi kısaltmalar kullanarak, tek karakterlik değişken adları kullanarak, boşluk Çıkarma :-için ifve ,için andkullanılarak setofyerine listof(bir kısa adı vardır ve bu durumda aynı sonuçları üretir) ve kullanma sort0(X,X)yerine is_sorted(X), çünkü ( is_sortedaslında bir işlev değil, Ben yaptım):

b([],0).
b([H|T],N):-N#=A+B+1,b(H,A),b(T,B),sort0([H|T],[H|T]).
c(X,Y):-setof(A,b(A,X),L),length(L,Y).

Bu oldukça kısa, ama daha iyisini yapmak mümkün. Anahtar kavrayış, [H|T]liste sözdizimleri devam ettikçe gerçekten de ayrıntılı. Lisp programcılarının bileceği gibi, bir liste temelde sadece temelde tuple olan cons hücrelerinden oluşur ve bu programın neredeyse hiçbir kısmı liste yerleşiklerini kullanmaz. Prolog birkaç çok kısa tuple sözdizimine sahiptir (favorim A-B, ancak ikinci favorim, A/Bburada kullanıyorum çünkü bu durumda okunması kolay hata ayıklama çıktısı üretiyor); ve ayrıca nil, iki karakterle sıkışmak yerine, listenin sonunda kendi tek karakterimizi seçebiliriz [](seçtim x, fakat temelde her şey işe yarıyor). Öyleyse yerine [H|T]kullanabiliriz T/Hve çıktı alabiliriz.b bu şöyle gözüküyor (tupl'lerdeki sıralama düzeninin listelerdekilerden biraz farklı olduğunu unutmayın, bu yüzden yukarıdakiler aynı değildir):

x/x/x/x/x
x/x/x/(x/x)
x/(x/x)/(x/x)
x/x/(x/x/x)
x/(x/x/x/x)
x/x/(x/(x/x))
x/(x/x/(x/x))
x/(x/(x/x/x))
x/(x/(x/(x/x)))

Bu, yukarıdaki iç içe geçmiş listelerden okumaktan daha zordur, ancak mümkündür; zihinsel olarak xs'yi atlayın ve /()bir kabarcık olarak yorumlayın (ya da sadece /içeriği yoksa, içeriği olmayan, dejenere bir balon gibi düz ()) ve öğelerin yukarıda listelenen sürüm sürümüyle bire 1 (bozuksa) yazışması var .

Elbette, bu liste gösterimi, daha kısa olmasına rağmen, büyük bir dezavantaja sahiptir; dilin içine yerleştirilmemiş sort0olduğundan, listemizin sıralanıp sıralanmadığını kontrol etmek için kullanamayız . sort0Yine de, oldukça ayrıntılı bir şekilde anlatılmış olsa da, elle yapmak çok büyük bir kayıp değildir (aslında, [H|T]listeyi el ile yapmak da tam olarak aynı bayt sayısına eşittir). Burada anahtar fikir listesi sıralanır eğer kuyruğu sıralanır eğer yazılı çekler gibi program, görmek olmasıdır onun kuyruğu sıralanmış ve benzeri edilir; çok fazla gereksiz kontrol var ve bundan faydalanabiliriz. Bunun yerine, ilk iki öğenin sıralı olduğundan emin olmak için kontrol edeceğiz (listenin kendisi ve tüm sonekleri kontrol edildikten sonra listenin sıralanmasını sağlar).

İlk eleman kolayca erişilebilir; bu sadece listenin başı H. İkinci unsur, erişmek için daha zordur, ancak mevcut olmayabilir. Neyse ki, x(Prolog'un genelleştirilmiş karşılaştırma operatörü aracılığıyla) düşündüğümüz tüm dosyalardan daha az @>=, bu yüzden bir singleton listesinin “ikinci öğesini” düşünebiliriz xve program iyi çalışır. Aslında ikinci elemana erişime gelince, en ters yöntem, temel durumda ve özyinelemeli durumda bdönen bir üçüncü argüman (bir çıkış argümanı) eklemektir ; bu, ikinci özyinelemeli çağrıdan bir çıktısı olarak kuyruğun başını tutabileceğimiz anlamına gelir ve tabii ki kuyruğun başı listenin ikinci elemanıdır. Şimdi şuna benziyor:xHBb

b(x,0,x).
b(T/H,N,H):-N#=A+B+1,b(H,A,_),b(T,B,J),H@>=J.

Temel durum yeterince basit (boş liste, 0 değerini döndür, boş listenin "ilk elemanı" dır x). Özyinelemeli dava öncekiyle aynı şekilde başlar (sadece T/Hgösterimde değil [H|T], Hek bir argüman olarak); ekstra argümanı kafanın özyinelemeli çağrısından almaz, ancak bunu Jözyinelemede çağrıda saklı tutarız. O zaman tek yapmamız gereken , listenin sona erdiğinden emin olmak Hiçin J(yani "listenin en az iki öğeye sahip olması durumunda, ikincisi büyük veya eşittir) olmalıdır.

Ne yazık ki, bu yeni tanımı ile birlikte setofönceki tanımını kullanmaya çalışırsak , bir uyumsuzluk yaratır, çünkü kullanılmayan parametreleri, istediğimiz gibi olmayan bir SQL gibi aşağı yukarı aynı şekilde ele alır . İstediğimizi yapmak için yeniden yapılandırmak mümkündür, ancak bu yeniden yapılandırma karakterleri tutar. Bunun yerine, daha uygun bir varsayılan davranışa sahip olan ve yalnızca iki karakterden oluşan, bize şu tanımları veren kullanıyoruz :cbGROUP BYfindallc

c(X,Y):-findall(A,b(A,X,_),L),length(L,Y).

Ve bu tam bir program; tersine kabarcık paternleri oluşturun, sonra onları saymak için tam bir bayt yükü harcayın ( findalljeneratörü bir listeye dönüştürmek için uzun zamana ihtiyacımız var, daha sonra lengthbu listenin uzunluğunu kontrol etmek için ne yazık ki sözlü olarak adlandırılmış , ayrıca bir fonksiyon bildirimi için kazan plakasını kullanacağız ).


"Prolog aslında bir harita yüklemi yoktur" : Prolog var maplist/2-8yüklemi Bu irade burada işler kısaltır emin değilim gerçi.
17'yi

@Fatalize: Huh, daha yeni bir sürümde eklenmiş gibi görünüyor. Sahip olduğum kurulum dokümantasyonunda değil ve pratikte çalışmıyor:| ?- maplist(reverse,[A,B]). uncaught exception: error(existence_error(procedure,maplist/2),top_level/0)

Bu gerçekten garip; maplist(SWI-Prolog ve SiCStus gibi) büyük Prolog dağılımları verilmiştir çok yaygın kullanılan yüklem
Fatalize

10

Mathematica, 68 bayt

Bahse girerim bu sıfırdan bir uygulama ile (Mathematica'da bile) yenilebilir, ancak işte yerleşik versiyon:

<<NumericalDifferentialEquationAnalysis`
Last@ButcherTreeCount[#+1]&

ButcherTreeCount0-indexed, bu nedenle [#+1], ve argümanına kadar tüm değerlerin bir listesini döndürür, bu nedenle Last@. Ama aksi takdirde bu fonksiyon için sadece yerleşiktir. Bununla birlikte, ilk satırın yaptığı paketin yüklenmesini gerektirir.


8
"Elbette Mathematica'nın bunun için bir yerleşimi var."
orlp
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.