Solucan Ömrü


28

şartlar

Bir solucan negatif olmayan tamsayılar herhangi listesidir ve onun en sağdaki (yani son ) eleman denir kafa . Eğer kafa 0 değilse, kurtçuk, kafayı içeren en uzun bitişik elemanlar bloğundan oluşan ve tüm elemanlarına en az baş kadar büyük olan aktif bir segmente sahiptir . Düşük aktif bölümü Örneğin 1 ile indirildiği baş aktif bölümü olan, sonsuz 3 1 2 3 2etkin bir kesite sahiptir 2 3 2, ve böylece, aktif bölümdür 2 3 1.

Evrim kuralları

Bir solucan, aşağıdaki gibi adım adım gelişir:

T adımında (= 1, 2, 3, ...),
    eğer kafa 0 ise: baş başlığını sil
    : aktif kısmı, azaltılmış aktif parçanın t + 1 birleştirilmiş kopyalarıyla değiştirin.

Gerçek : Herhangi bir solucan sonunda boş listeye evrilir ve bunu yapmak için atılacak adımların sayısı solucanın ömrüdir .

( LD Beklemişev'in bir makalesi olan The Worm Principle'de detaylar bulunabilir . Sonlu bir sekans için "list" ve son elementini ifade etmek için "head" kullanımı bu makaleden alınmıştır - karıştırılmamalıdır) listelerin genel olarak kullanımı , başın genellikle ilk öğe olduğu soyut veri türü olarak kullanılır .

Örnekler (parantez içindeki aktif bölüm)

Solucan: 0,1

step    worm
         0(1)
1        0 0 0
2        0 0 
3        0
4           <- lifetime = 4

Solucan: 1,0

step    worm
         1 0
1       (1)
2        0 0 0
3        0 0 
4        0
5           <- lifetime = 5

Solucan: 1,1

step    worm
        (1 1)
1        1 0 1 0 
2        1 0(1) 
3        1 0 0 0 0 0
4        1 0 0 0 0
5        1 0 0 0
...
8       (1) 
9        0 0 0 0 0 0 0 0 0 0
10       0 0 0 0 0 0 0 0 0
...
18       0
19           <- lifetime = 19

Solucan: 2

step    worm
        (2)
1       (1 1)
2        1 0 1 0 1 0
3        1 0 1 0(1)
4        1 0 1 0 0 0 0 0 0
5        1 0 1 0 0 0 0 0
6        1 0 1 0 0 0 0
...
10       1 0(1)
11       1 0 0 0 0 0 0 0 0 0 0 0 0 0
12       1 0 0 0 0 0 0 0 0 0 0 0 0
...
24      (1)
25       0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...
50       0
51          <- lifetime = 51

Solucan: 2,1

        (2 1)
1        2 0 2 0
2        2 0(2)
3        2 0(1 1 1 1)
4        2 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0
5        2 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0(1 1 1)
6        2 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
7        2 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0(1 1)
8        2 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0{1 0}^9
...
??          <- lifetime = ??      

Solucan: 3

step    worm
        (3)
1       (2 2)
2       (2 1 2 1 2 1)
3        2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0 
4        2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1(2)
5        2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0(2 1 2 1 1 1 1 1 1 1)
6        2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0{2 1 2 1 1 1 1 1 1 0}^7
7        2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0{2 1 2 1 1 1 1 1 1 0}^6 (2 1 2 1 1 1 1 1 1) 
...      ...
??          <- lifetime = ??


bir kenara

Solucan ömürleri, f α'nın standart hızlı büyüyen fonksiyon hiyerarşisi açısından aşağıdaki alt sınırlarla gösterildiği gibi tipik olarak muazzamdır :

worm                lower bound on lifetime
----------------    ------------------------------------------
11..10 (k 1s)       f_k(2)
2                   f_ω(2)
211..1 (k 1s)       f_(ω+k)(2)
2121..212 (k 2s)    f_(ωk)(2)
22..2 (k 2s)        f_(ω^k)(2)
3                   f_(ω^ω)(2)
...
n                   f_(ω^ω^..^ω)(2) (n-1 ωs)  >  f_(ε_0) (n-1)

Dikkat çekici bir şekilde, solucan [3] zaten Graham’ın sayısını , G’yi aşan bir ömre sahip :

f ω ω (2) = f ω 2 (2) = f ω2 (2) = f ω + 2 (2) = f ω + 1 (f ω + 1 (2)) >> f ω + 1 (64) > G.


Code Golf Mücadelesi

Mümkün olan en kısa fonksiyonu olan alt programı aşağıdaki davranışla yazın:

Giriş : Herhangi bir kurt.
Çıktı : Solucanın ömrü.

Kod boyutu bayt cinsinden ölçülür.


İşte bir örnek (Python, golf yaklaşık 167 bayta kadar):

from itertools import *
def T(w):
    w=w[::-1]
    t=0
    while w:
        t+=1
        if w[0]:a=list(takewhile(lambda e:e>=w[0],w));a[0]-=1;w=a*(t+1)+w[len(a):]
        else:w=w[1:]
    return t


Not : Eğer t (n) solucanın ömrü [n] ise, o zaman t (n) 'nin büyüme oranı kabaca Goodstein fonksiyonununkidir . Yani bu 100 bayt aşağıda golfed edilebilirse, iyi bir kazanan cevabı verebilir Büyük Numara Yazdırılabilir soruya . (Bu cevap için, büyüme hızı her zaman n-adım sayacını her zaman n - solucanın [n] ile aynı değeri - 0'da başlatmak yerine) başlatarak büyük ölçüde hızlandırılabilir.)


Kodunuzla kafam karıştı. Kafanın en sağdaki eleman olduğunu söylediniz , ancak Python örneğinizde, başa w[0]o listenin * en soldaki elemanı olarak bakıyorsunuz.

@LegoStormtroopr Eğer bir listeyi sola ve sağa sahip olarak düşünebilirsiniz. Sadece bir ilkini ve sonunu düşünürseniz, ilk dizgiyi okurken en sağdan ilke veya sonuncuya eşleyebilirsiniz - bu sorunun bir parçası değildir. Ancak işlev girişleri de kesin olarak tanımlanmadı.
Bob

@LegoStormtroopr - İyi yakalama; Başının gerçekten sağda olması gereken giriş solucanını tersine çevirecek bir çizgi ekleyerek kodu düzelttim (yani w listesindeki son öğe). Programın tersine çevrilmiş solucan üzerinde çalışması verimlilik içindir.
res

Doğru Alma cevabı için 2 1makul bir süre içinde istemek çok olabilir, ama yararlı bir testtir dizisi başlaması gerektiğini (2 1), 2 0 2 0, 2 0 (2), 2 0 (1 1 1 1), ...
Peter Taylor

1
@ ThePlasmaRailgun - Harvey Friedman’ın ifadesine göre, hızlı büyüyen hiyerarşideki (solucan ömürleri gibi) ε_0 seviyesindeki fonksiyonlardan türetilen sayılar, TREE’ye (3) kıyasla tamamen BİLDİRİLEMEZ .
res

Yanıtlar:


15

GolfScript ( 56 54 karakter)

{-1%0\{\)\.0={.0+.({<}+??\((\+.@<2$*\+}{(;}if.}do;}:L;

Çevrimiçi demo

Bence buradaki anahtar numara muhtemelen solucanı ters sırada tutmaktır. Bu, aktif segmentin uzunluğunu bulmak için oldukça kompakt olduğu anlamına gelir: .0+.({<}+??(burada 0kafadan daha küçük bir eleman bulmamızı sağlamak için bir koruyucu olarak eklenir).


Bir yana, solucan ömrünün bir analizi. Ben solucan belirtmek gerekir age, head tailkafasında tekrarlanmasını ve kuyruk belirtmek için üslerin kullanarak (Sorunun gösterimden ters sırada yani): örn 2^3olduğunu 2 2 2.

Lemma : herhangi bir aktif bölümü için xs, bir fonksiyon vardır f_xsöyle ki age, xs 0 taildönüşümleri içine f_xs(age), tail.

Kanıt: hiçbir aktif segment asla a içeremez 0, bu nedenle kuyruktan önceki her şeyi sildiğimiz zaman yaş kuyruktan bağımsızdır ve bu nedenle sadece bir fonksiyondur xs.

Lemma : Herhangi bir aktif segment için xs, solucan age, xsyaşta ölür f_xs(age) - 1.

İspat: önceki lemmaya göre age, xs 0dönüşür f_xs(age), []. Son adım, 0daha önce dokunulmamış olanın silinmesidir, çünkü aktif bir segmentin hiçbir zaman bir parçasını oluşturamaz.

Bu iki lemmada ile bazı basit aktif segmentleri çalışabiliriz.

için n > 0,

age, 1^n 0 xs -> age+1, (0 1^{n-1})^{age+1} 0 xs
              == age+1, 0 (1^{n-1} 0)^{age+1} xs
              -> age+2, (1^{n-1} 0)^{age+1} xs
              -> f_{1^{n-1}}^{age+1}(age+2), xs

öyleyse f_{1^n} = x -> f_{1^{n-1}}^{x+1}(x+2)(temel durumda f_{[]} = x -> x+1veya tercih ederseniz f_{1} = x -> 2x+3). Ackermann – Péter fonksiyonunun f_{1^n}(x) ~ A(n+1, x)nerede Aolduğunu görüyoruz .

age, 2 0 xs -> age+1, 1^{age+1} 0 xs
            -> f_{1^{age+1}}(age+1)

Bu konuyu ele almak için yeterlidir 1 2( 2 1soru yazımında):

1, 1 2 -> 2, 0 2 0 2
       -> 3, 2 0 2
       -> f_{1^4}(4), 2
       -> f_{1^{f_{1^4}(4)+1}}(f_{1^4}(4)+1) - 1, []

Böylece verilen girdi 2 1çıktı bekliyoruz ~ A(A(5,4), A(5,4)).

1, 3 -> 2, 2 2
     -> 3, 1 2 1 2 1 2
     -> 4, 0 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2
     -> 5, 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2 0 2 1 2 1 2
     -> f_{21212}^4(5) - 1

age, 2 1 2 1 2 -> age+1, (1 1 2 1 2)^{age+1}
               -> age+2, 0 1 2 1 2 (1 1 2 1 2)^age
               -> age+3, 1 2 1 2 (1 1 2 1 2)^age

ve bu fonksiyonun neden bu kadar delice büyüdüğünü gerçekten anlamaya başladım.


Çok havalı. Bence bu program da kazanacak bir cevap verecek. , çıktı büyüklüğü Graham'ın sayısını aşan En Son sonlandırma programına . (Mevcut kazanan 63 byte Haskell kodu.) Örneğin, 55 baytta, (sözdizimi hatalarına eğilimli olduğum için) gibi bir şey9{-1%0\{\)\.0={.0+.({<}+??\((\+.@<2$*\+}{(;}if.}do;}:L~ Graham'ın sayısını aşan solucanın ömrünü hesaplar - ve daha da golf oynadı.
res

9

GolfScript, 69 62 karakter

{0:?~%{(.{[(]{:^0=2$0+0=<}{\(@\+}/}{,:^}if;^?):?)*\+.}do;?}:C;

İşlev Cküme solucanını bekler ve sonuçtan değiştirir.

Örnekler:

> [1 1]
19

> [2]
51

> [1 1 0]
51

Fantastik! Elbette, bu "Biraz Yazdırılabilir Sayı" sorusu için kesin bir kazanan verecek şekilde biraz da değiştirebilirsiniz .
res

Orada bir şey yayınladığını görmedim, bu yüzden devam ettim ve bu kodun şu ana kadar kazanan cevap olduğuna inandığım bir değişiklik yaptım - *ve ^çarpımın aritmetik operatörleri olarak kullanılmadığını farz ediyorum . ve üstel. Kuşkusuz, oradaki kendi cevabınızı (şüphesiz üstün) cevaplamak istiyorsanız, benimkini mutlu bir şekilde kaldıracağım.
res

7

Ruby - 131 karakter

Bunun yukarıdaki GolfScript çözümleriyle rekabet edemeyeceğini biliyorum ve bunun bir puan veya daha fazla karakter azaltılabileceğinden oldukça eminim, ama dürüst olmak gerekirse, çözülmemiş sorunu çözebildiğim için mutluyum. Harika bir yapboz!

f=->w{t=0;w.reverse!;until w==[];t+=1;if w[0]<1;w.shift;else;h=w.take_while{|x|x>=w[0]};h[0]-=1;w.shift h.size;w=h*t+h+w;end;end;t}

Yukarıdakilerin türetildiği ön-golf çözümüm:

def life_time(worm)
  step = 0
  worm.reverse!
  until worm.empty?
    step += 1
    if worm.first == 0
      worm.shift
    else
      head = worm.take_while{ |x| x >= worm.first }
      head[0] -= 1
      worm.shift(head.size)
      worm = head * (step + 1) + worm
    end
  end
  step
end

Genel ipucu: birçok golf problemi negatif olmayan tamsayılar üzerinde çalışır, bu durumda if foo==0düzeltilebilir if foo<1. Bu size burada bir karakter kazandırabilir.
Peter Taylor

Bu arada, bunun bir saniye olmadan çalışmasını büyüleyici buluyorum reverse.
Peter Taylor

Ah, değil. Sadece test durumlarında çalışır, çünkü sadece palindromik aktif bölümleri vardır.
Peter Taylor

Golf bahşiş için teşekkürler, PeterTaylor. Ayrıca, eksik ikinci geri viteste iyi yakalama. Onu ekledim. Bunu daha sonra tersini kullanmadan başka bir şekilde yeniden yazmaya çalışacağım. Ben çok emin alabilirim olduğum elsebir satır maddesini aşağı ve sonra takas if..else..endbir üçlü ifadesi için. Birkaç karakter kaydetmek için bir lambda kullanabilirim, sanırım.
OI

6

Sclipting (43 karakter)

글坼가⑴감套擘終長①加⒈丟倘⓶增⓶가采⓶擘❷小終⓷丟❶長貶❷가掊貶插①增復合감不가終終

Bu, girişi boşlukla ayrılmış bir liste olarak bekler. Bu, doğru cevabı verir.1 1 ve 2fakat için 2 1veya 3çok uzun bu yüzden bitmesini bekleyen verdi alır.

Yorum ile:

글坼 | split at spaces
가⑴ | iteration count = 0

감套 | while:
  擘終長①加⒈丟 | remove zeros from end and add to iteration count
  倘 | if the list is not empty:
    ⓶增⓶ | increment iteration count
    가采⓶擘❷小終⓷丟 | separate out active segment
    ❶長貶❷가掊貶插 | compute reduced active segment
    ①增復合 | repeat reduced active segment and concat
    감 | continue while loop
  不 | else
    가 | stop while loop
  終 | end if
終 | end while

2
Bir tercümana bağlantı kullanışlı olabilir ... Ayrıca, UTF-16 kullanarak 86 bayt?
Peter Taylor

@PeterTaylor: Teşekkürler, yazıya tercümanın bağlantısını ekledi. Ve evet, 43 BMP karakteri UTF-16'da 86 bayta çevriliyor.
Timwi

5

k (83)

worm:{-1+*({x,,(,/((x+:i)#,@[y@&w;(i:~~#y)#0;-1+]),y@&~w:&\~y<*y;1_y)@~*y}.)/(1;|,/x)}

bu muhtemelen daha fazla golf oynayabilir, çünkü nüksü oldukça basit bir şekilde gerçekleştirir.

temel evrim işlevi, {x,,(,/((x+:i)#,@[y@&w;(i:~~#y)#0;-1+]),y@&~w:&\~y<*y;1_y)@~*y}65 karakterdir ve solucanın öldüğü yaşı artırmayı durdurmak için bazı püf noktaları kullanır. sarıcı, listeye tek bir tamsayı girişini zorlar, girişi tersine çevirir (gösterimi tersine çeviren bir solucan cinsinden yinelemeyi yazmak daha kısadır), tespit noktasını sorar, çıktısını yaş olarak seçer ve sonucu ayarlar Son nesildeki atışı hesaba katmak.

baskıyı zorlarsam ve manuel olarak iptal edersem, 80'e düşer ({-1+*({x,,(,/((x+:i)#,@[y@&w;(i:~~#y)#0;-1+]),y@&~w:&\~y<*y;1_y)@~*y}.)/(1;x)} ) .

bazı örnekler:

  worm 1 1 0
51
  worm 2
51
  worm 1 1
19

ne yazık ki, çok yavaş, 64 bit tamsayılarla sınırlı ve muhtemelen hafıza açısından verimli olmadığı için, çok teorik anlamda hariç, muhtemelen En Büyük Sayı Baskısı için çok fazla kullanılmaz .

Özellikle, worm 2 1ve worm 3sadece yayık (ve muhtemelen atardı 'wsfullben onları devam ediyoruz izin verirsen () bellek yetersiz).


Programınızı bu çevrimiçi tercüman ile çalıştırmayı denedim , ancak herhangi bir çıktı göstermiyor. (.K uzantılı bir metin dosyası göndermenin K yorumlayıcısını çağırması gerekir.) Çıktıyı stdout'a göndermek için ne yapılabileceğini biliyor musunuz?
res

Açık kaynaklı bir k3 klonu olan kona çalışıyor gibi görünüyor. Kodum k4 ile yazılmıştır ve k3 ile uyumlu olması muhtemel değildir. Kx.com/software-download.php adresinden q / k4'ün zaman sınırlı bir ücretsiz kopyasını alabilirsiniz ; Bunu ` to switch from yaptıktan sonra k, REPL'i başlatın, q` yazıp kodumu yapıştırın. Alternatif olarak, kodumu .kuzantılı bir dosyaya kaydedebilir ve yorumlayıcıya yükleyebilirsiniz.
Aaron Davies

2

APL (Dyalog Unicode) , 52 bayt SBCS

@Ngn ve @ Adám sayesinde 7 bayt kaydedildi.

0{⍬≡⍵:⍺⋄n←⍺+10=⊃⍵:n1↓⍵⋄n∇∊(⊂1n/-∘1@1¨)@1⊆∘⍵⍳⍨⌊\⍵}⌽

Çevrimiçi deneyin!

Açıklama:

0{...}⌽     A monadic function train. We define a recursive function with two
            arguments: zero (our counter), and the reverse of our input
⍬≡⍵:⍺       Our base case - if our input is an empty list, return our counter
n←⍺+1       Define 'n' as our counter plus 1
0=⊃⍵:n1↓⍵  If the first element of the input is zero, recurse with the tail
            of our input and n
\⍵         Minimum-expand: creates a new list from our input where each element
            is the incremental minimum     
⍳⍨          Applies above to both sides of the index-of function. Index-of returns
            the index of the first occurence of each element in the left-side list.
            At this point, a (reversed) input list of [3 4 5 2 3 4] would result
            in [1 1 1 4 4 4]
⊆∘⍵         Partition, composed with our input. Partition creates sublists of the
            right input whenever the integer list in the left input increases.
            This means we now have a list of sub-lists, with the first element
            being the worm's active segment.
(...)@1    ⍝ Take the active segment and apply the following function train...
-∘1@1¨     ⍝ Subtract 1 from the first element of the active segment
1n/        ⍝ Replicate the resultant list above n+1 times
⊂          ⍝ Enclose the above, so as to keep the original shape of our sub-array
∊          ⍝ Enlist everything above together - this recursively concatenates our
           ⍝ new active segment with the remainder of the list
n∇         ⍝ Recurse with the above and n

APL'nin bunun için gerçekten temiz bir çözümü olacağını düşündüm, dizi tabanlı bir dil değil mi?
ThePlasmaRailgun

1

Scala, 198

type A=List[Int]
def T(w:A)={def s(i:Int,l:A):Stream[A]=l match{case f::r=>l#::s(i+1,if(f<1)r
else{val(h,t)=l.span(_>=l(0));List.fill(i)(h(0)-1::h.tail).flatten++t})
case _=>Stream()};s(2,w).length}

Kullanımı:

scala> T(List(2))
res0: Int = 51

1

K, 95

{i::0;#{~x~,0}{((x@!b),,[;r]/[i+:1;r:{@[x;-1+#x;-1+]}@_(b:0^1+*|&h>x)_x];-1_x)@0=h:*|x:(),x}\x}

.

k)worm:{i::0;#{~x~,0}{((x@!b),,[;r]/[i+:1;r:{@[x;-1+#x;-1+]}@_(b:0^1+*|&h>x)_x];-1_x)@0=h:*|x:(),x}\x}
k)worm 2
51
k)worm 1 1
19
q)worm 1 1 0 0 0 0
635

1

C (gcc) , 396 bayt

#define K malloc(8)
typedef*n;E(n e,n o){n s=K,t=s;for(*s=*o;o=o[1];*t=*o)t=t[1]=K;t[1]=e;e=s;}main(c,f,l,j,a)n*f;{n w=K,x=w;for(;l=--c;x=x[1]=K)*x=atoi(f[c]);for(;w&&++l;)if(*w){n v=K,z=v,u=w,t=K;for(a=*v=*w;(u=u[1])&&*u>=*w;*z=*u)z=z[1]=K;for(x=v[1],v=K,*v=a-1,1[u=v]=x;u;u=u[1])w=w[1];for(j=~l;j++;)u=t=E(t,v);for(;(u=u[1])&&(x=u[1])&&x[1];);u[1]=0;w=w?E(w,t):t;}else w=w[1];printf("%d",--l);}

Çevrimiçi deneyin!

Partiye son derece geç kaldığımı biliyorum, ancak bağlantılı liste uygulaması gerektiren C’de elimi deneyeceğimi düşündüm. Tüm tanımlayıcıları tek karakterlere çevirmenin yanı sıra pek de golf değil, ama çalışıyor!

Sonuçta, bunun şimdiye kadar yazdığım 3. C / C ++ programı olduğunu düşünüyorum.


Gerçekten bağlantılı bir listeye ihtiyacınız var mı? Neden sadece dizileri ayırmıyorsunuz? Bu kod golf olduğundan, işiniz bittiğinde onları serbest bırakmanıza bile gerek yok. Sen belki hatta çağrı yığını (emin değilim) onları saklamak için bir yol bulmak mümkün.
dfeuer

Ayrıca, bir ana işleve ihtiyacınız yok. Sadece solucanı argüman olarak alan ve ömrünü döndüren bir işlev yazın. Solucan, bir dizi ve uzunluğu ya da negatif bir sayıyla biten bir dizi olabilir.
dfeuer

1

Haskell , 84 bayt

(0!).reverse
n!(x:y)|x<1=(n+1)!y|(a,b)<-span(>=x)y=(n+1)!(([-1..n]*>x-1:a)++b)
n!_=n

Çevrimiçi deneyin!

İki bayt için @xnor'a teşekkürler.

Genel artışı artırmak için iyi bir yol olması gerektiğini düşünüyorum, ancak henüz kısa bir şey bulamadım.


1
İki küçük golf : boş liste vakasını kontrol et, ve n1 ile aşağı
kay

Ayrıca (n+1)!iki kez yazmamanın bir yolu olması gerektiğini düşünüyorum , ancak girişimim yalnızca bağlı kaldı.
xnor


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.