En verimli ikili fonksiyonu hesaplayın


13

Bugün en verimli ikili fonksiyonu hesaplayacağız. Daha spesifik olarak, işlevi sabit giriş 0'a veya kendi çıktısına uygulamaktan bir ifade oluşturulduğunda, mümkün olan en kısa ifadelere sahip tüm pozitif tamsayıları temsil edebilen ve daha küçük tamsayılara daha yüksek öncelik veren işlevi hesaplayacağız.

Bu işlev aşağıdaki gibi oluşturulmuştur:

Her tamsayı için, 1'den başlayıp yukarı doğru, henüz bir çıktı atamadığımız en kısa ifadeyi seçin ve bu tamsayıyı o ifadenin çıktısını yapın. İfade uzunluğundaki bağlar daha küçük sol argüman ve sonra daha küçük sağ argüman tarafından kesilir. Şöyle çalışır:

  • Başlangıçta, 1 atanmamış. Atanmamış en kısa ifade f(0, 0), bu yüzden bunu 1 olarak ayarlayacağız.

  • Şimdi, 2 atanmamış. Atanmamış en kısa ifadeler f(f(0, 0), 0)= f(1, 0)ve f(0, f(0, 0))= şeklindedir f(0, 1). Bağlar daha küçük sol argümana doğru kırılıyor f(0, 1) = 2.

  • Atanmayan en kısa ifade f(f(0, 0), 0)= f(1, 0), yani f(1, 0) = 3.

  • Şimdi, sadece 2 fs ve 3 0s ifadelerimiz kalmadı, bu yüzden her birine bir tane daha eklememiz gerekecek. Bağları sol argümanla, sonra sağ argümanla koparıyoruz, o f(0, 2) = 4zamandan beri f(0, f(0, f(0, 0))) = f(0, f(0, 1)) = f(0, 2).

  • Sürekli, elimizdeki f(0, 3) = 5, f(1, 1) = 6, f(2, 0) = 7, f(3, 0) = 8, f(0, 4) = 9, ...

İlk birkaç değer için doldurduğum bir tablo:

    0  1  2  3  4  5  6  7  8
 /---------------------------
0|  1  2  4  5  9 10 11 12 13
1|  3  6 14 15 37 38 39 40 41
2|  7 16 42 43
3|  8 17 44 45
4| 18 46
5| 19 47
6| 20 48
7| 21 49
8| 22 50

Buna bakmanın bir başka yolu, her çıktının, girdilerinin artı bir boyutunun toplamına eşit bir boyuta sahip olmasıdır. Tablo, artan çıktı boyutu sırasına göre doldurulur, sol giriş sonra sağ giriş en aza indirilerek bağlar kopar.

Bu işlevin değerini girdi, hesapla ve çıktı olarak negatif olmayan iki tam sayı verildi. Bu kod golf. Bayt cinsinden en kısa çözüm kazanır. Standart boşluklar yasaklanmıştır.


A072766'ya benzer , ancak f (3, 1) 'den farklıdır.
kennytm

2
Bu, beni verimli bir şekilde hesaplamam için bir zamanlar bulmaca yapan bir süredir ilk zorluk. Katalanca rakamlarla bir şeylerin mümkün olduğuna inanıyorum, ancak hemen bir çözüm düşünemiyorum. Hmm ...
orlp

2
Pekala, bu yüzden iyi bir golf cevabı vereceğini düşünmüyorum, ancak makul bir şekilde verimli hale getirmek için yapabileceğiniz şey, Katalan sayılarını bir sonraki Katalan numarasından daha küçük olana kadar fonksiyon argümanlarından tekrar tekrar çıkarmaktır. Sonra ifadelerinin uzunluğunu buldunuz. Ardından , sonucu hesaplamak için bu kağıttan sıralama / çözme işlevlerini modifikasyonla kullanabilirsiniz. Belki de tüm bunları yaptıktan sonra, ortadaki kod parçalarını 'iptal etmek' ve makul derecede zarif bir çözüm bulmak mümkündür.
orlp

Aslında önceki yorumumdaki yaklaşım işe yaramıyor. ((0, (0, (0, 0))), 0)sözlükbilimsel olarak daha küçüktür (((0, 0), 0), (0, 0)), ancak ikincisinin sol tarafı daha küçüktür.
orlp

Yanıtlar:


6

Haskell, 110 bayt

f q=head[i|let c=[(-1,0)]:[[(f a,f b)|n<-[0..k],a<-c!!n,b<-c!!(k-n)]|k<-[0..]],(p,i)<-zip(concat c)[0..],p==q]

Buradaki argüman bir demet olarak alınmıştır (x,y). Yukarıdaki cevaba oldukça benzer, ancak arama listesi ağaçlar yerine sadece sol ve sağ endeks çiftlerini tutar.


1
Güzel cevap! head[...]olduğu [...]!!0ve (p,i)<-zip(concat c)[0..]için kısaltılabilir (i,p)<-zip[0..]$id=<<c.
Laikoni

Gelişmeler için teşekkürler! Kesinlikle id=<<repertuar ekleme :)
halfflat

5

Python 3, 154 bayt

b=lambda n:[(l,r)for k in range(1,n)for l in b(k)for r in b(n-k)]+[0]*(n<2)
def f(x,y):r=sum((b(n)for n in range(1,x+y+3)),[]);return r.index((r[x],r[y]))

Çok hızlı veya çok golf değil, ama bir başlangıç.


5

Vaov! Aslında etkili bir hesaplama algoritması yapmayı başardım. İlk başta bunu beklemiyordum. Çözüm oldukça zarif. Art arda daha fazla kesinti yapar, sonra 0 temel durumuna kadar geri çekilir. Bu cevapta C (n) işlevi Katalan sayılarını gösterir .

Kritik ilk adım, C (0) = 1 uzunluk uzunluğunun (yani 0'ın kendisi), C (1) = 1 uzunluk uzunluğunun (yani f (0, 0)), C (2) = olduğunu kabul etmektir. 2 uzunluk iki değeri (f (0, f (0, 0)) ve f (f (0, 0), 0)).

Bu, n'inci ifadeyi ararsak ve en büyük k'yi C (0) + C (1) + ... + C (k) <= n olacak şekilde bulursak, n'nin k uzunluğuna sahip olduğunu biliyoruz. .

Ama şimdi devam edebiliriz! Çünkü aradığımız ifade uzunluk sınıfındaki n - C (0) - C (1) - ... - C (k).

Şimdi, sol segmentin uzunluğunu ve ardından bu alt bölümdeki sıralamayı bulmak için benzer bir hile kullanabiliriz. Ve sonra bulduğumuz rütbelerimizi tekrarlayın!

Bir göz açıp kapayıncaya kadar f (5030, 3749) = 1542317211 bulundu.

Python, rakipsiz

def C(n):
    r = 1
    for i in range(n):
        r *= 2*n - i
        r //= i + 1
    return r//(n+1)

def unrank(n):
    if n == 0: return 0

    l = 0
    while C(l) <= n:
        n -= C(l)
        l += 1

    right_l = l - 1
    while right_l and n >= C(l - 1 - right_l) * C(right_l):
        n -= C(l - 1 - right_l) * C(right_l)
        right_l -= 1

    right_num = C(right_l)

    r_rank = n % right_num
    l_rank = n // right_num

    for sz in range(l - 1 - right_l): l_rank += C(sz)
    for sz in range(right_l): r_rank += C(sz)

    return (unrank(l_rank), unrank(r_rank))

def rank(e):
    if e == 0: return 0
    left, right = e

    l = str(e).count("(")
    left_l = str(left).count("(")
    right_l = str(right).count("(")
    right_num = C(right_l)

    n = sum(C(sz) for sz in range(l))
    n += sum(C(sz)*C(l - 1 - sz) for sz in range(left_l))

    n += (rank(left) - sum(C(sz) for sz in range(left_l))) * C(right_l)
    n += rank(right) - sum(C(sz) for sz in range(right_l))

    return n

def f(x, y):
    return rank((unrank(x), unrank(y)))

Bir sürü gereksiz hesaplama yaptığımdan oldukça eminim ve birçok orta adım kaldırılabilir.

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.