ワームの寿命


28

条項

ワームは、非負の整数のいずれかのリストであり、その右端の(すなわち、最後の)要素が呼ばれているヘッド。headが0でない場合、ワームは、headを含む要素の最も長い連続したブロックで構成されるアクティブなセグメントを持ち、すべての要素は少なくともheadと同じ大きさです。減少活性セグメントはたとえば1だけデクリメントヘッドとアクティブなセグメントであり、ワームが3 1 2 3 2アクティブなセグメントを有し2 3 2、縮小アクティブセグメントです2 3 1

進化のルール

ワームは、次のように段階的に進化します。

ステップt(= 1、2、3、...)で
    、ヘッドが0の場合:ヘッドを削除する
    else:アクティブセグメントを、縮小されたアクティブセグメントのt + 1連結コピーで置き換える。

事実ワームは最終的に空のリストに進化し、そのためのステップ数はワームの存続期間です。

(詳細はThe Worm Principle、LD Beklemishevの論文に記載されています。有限リストを意味する「リスト」、およびその最後の要素を意味する「頭」の使用法は、この論文から引用されています。リストの一般的な使用法は抽象データ型であり、通常head最初の要素を意味します。)

例(括弧内のアクティブなセグメント)

ワーム:0,1

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

ワーム:1,0

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

ワーム: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

ワーム: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

ワーム: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 = ??      

ワーム: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 = ??


さておき

ワームの寿命は、通常、関数fαの標準的な急成長階層に関する次の下限で示されるように、非常に長いです。

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)

驚くべきことに、ワーム[3]にはすでにGrahamの数 G をはるかに超える寿命があります。

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


コードゴルフチャレンジ

次の動作を使用して、可能な限り短い関数サブプログラムを作成します。

入力:ワーム。
出力:ワームの寿命。

コードサイズはバイト単位で測定されます。


次に例を示します(Python、約167バイトのゴルフ):

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


注意:t(n)がワームの寿命[n]である場合、t(n)の成長率はおおよそGoodstein関数の成長率です。そのため、これを100バイト未満にゴルフできる場合、印刷可能な最大数の質問に勝利の答えを与えることができます。(その答えとして、ステップカウンターを常に0から開始するのではなく、ワーム[n]と同じ値から開始することにより、成長率を大幅に加速することができます。)


私はあなたのコードに混乱しています。ヘッドは右端の要素であると言いましたが、Pythonの例では、ヘッドw[0]をそのリストの*左端の要素として扱いますか?

@LegoStormtrooprリストに左右があるとみなすことができる場合。最初と最後を考慮するだけであれば、最初の文字列を読み取るときに、右端を最初または最後にマッピングできます-これは質問の一部ではありません。しかし、関数の入力も厳密には定義されていません。
ボブ14年

@LegoStormtroopr-良いキャッチ。入力ワームを反転する行を追加してコードを修正しました。入力ワームのヘッドは実際に右側(つまり、リストwの最後の要素)にあるはずです。プログラムが逆ワームで動作するのは効率のためです。
解像度14年

正しい取得答えのためには、2 1合理的な時間内に尋ねることが多すぎるかもしれないが、有用な試験シーケンスを開始すべきであるということです(2 1)2 0 2 02 0 (2)2 0 (1 1 1 1)、...
ピーター・テイラー

1
@ThePlasmaRailgun-Harvey Friedmanを言い換えると、急成長している階層のレベルε_0の関数(ワームの寿命など)から派生した数値は、TREE(3)と比較し完全に気付かれません
解像度の

回答:


15

GolfScript(56 54文字)

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

オンラインデモ

ここでの重要なトリックは、おそらくワームを逆の順序に保つことだと思います。それはアクティブなセグメントの長さを見つけるために、かなりコンパクトだということを意味する:.0+.({<}+??0ガードとして添加されるが、我々はヘッドよりも小さい要素を見つけることを保証します)。


余談ですが、ワームの寿命に関するいくつかの分析。私はとワームを表しますage, head tail頭と尾で繰り返しを示すために、指数を使用して(質問者の表記から逆の順序でIE):たとえば2^3れます2 2 2

補題:アクティブなセグメントにxs、機能が存在するf_xsようにage, xs 0 tail変換にはf_xs(age), tail

証明:アクティブなセグメントにaを含めることはできない0ため、テールを削除するまでの経過時間はテールとは無関係であるため、のみの関数になりxsます。

補題:活動中のセグメントxsでは、このワームage, xsは年齢で死にf_xs(age) - 1ます。

証明:前の補題により、にage, xs 0変換されf_xs(age), []ます。最後のステップは、その0セグメントの削除です。これは、アクティブなセグメントの一部を形成することはできないため、以前は変更されていません。

これら2つの補題を使用して、いくつかの単純なアクティブセグメントを学習できます。

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

そのためf_{1^n} = x -> f_{1^{n-1}}^{x+1}(x+2)(ベースケース付きf_{[]} = x -> x+1、または必要に応じてf_{1} = x -> 2x+3)。Ackermann–Péter関数がf_{1^n}(x) ~ A(n+1, x)どこにあるかAがわかります。

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

1 22 1質問の表記法で)ハンドルを取得するにはこれで十分です。

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, []

したがって、入力が与えられる2 1と、出力〜が期待されます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

そして、この機能が非常に異常に大きくなる理由を本当に理解し始めることができます。


とてもかっこいい。また、このプログラムは、出力サイズがGrahamの数を超える最短の終了プログラムに対しても勝利の答えを与えると思います。(現在の勝者は63バイトのHaskellコードです。)たとえば、55バイトで(構文エラーになりやすいので)9{-1%0\{\)\.0={.0+.({<}+??\((\+.@<2$*\+}{(;}if.}do;}:L~グラハムの数をはるかに超えるワームの寿命を計算します[9]さらにゴルフ。
解像度14年

9

GolfScript、69 62文字

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

この関数Cは、スタック上のワームを予期し、結果で置き換えます。

例:

> [1 1]
19

> [2]
51

> [1 1 0]
51

素晴らしい!これを少し修正して、「最大印刷可能数」の質問の明確な勝者を与えることもできます。
解像度14年

私はあなたがそこに何かを投稿するのを見なかったので、私は先に進んで、これまでの勝利の答えであると信じるものとしてこのコードの修正を投稿しました - *^は乗算の算術演算子として使用されていないと仮定します累乗します。確かに、あなたがそこにあなた自身の(疑いもなく優れた)答えを提出したいなら、私は喜んで私のものを削除します。
解像度14年

7

ルビー— 131文字

これは上記のGolfScriptソリューションと競合できないことを知っており、これによりスコアを1文字以上減らすことができると確信していますが、正直なところ、この問題を解決できたことをうれしく思います。素晴らしいパズル!

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}

上記の派生元である私のゴルフ前のソリューション:

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

一般的なヒント:多くのゴルフの問題は、負でない整数で機能if foo==0if foo<1ます。この場合、にトリミングできます。ここで1文字節約できます。
ピーターテイラー14年

ちなみに、これがすぐに機能するのは魅力的ですreverse
ピーターテイラー14年

ああ、そうではありません。それらはパリンドロームのアクティブなセグメントのみを持っているため、テストケースでのみ機能します。
ピーターテイラー14年

ゴルフのヒント@PeterTaylorに感謝します。また、行方不明の2番目の逆の良いキャッチ。追加しました。後でリバースを使用せずに、この別の方法で書き直そうとします。else句を1行にまとめてif..else..endから、3項のステートメントに交換できると確信しています。ラムダを使用していくつかの文字を保存することもできると思います。
OI 14年

6

スクリプティング(43文字)

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

これは、スペースで区切られたリストとしての入力を想定しています。これにより、1 1およびの正解が出力されます2が、2 1または3に時間がかかりすぎるため、終了するのをあきらめました。

解説付き:

글坼 | 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
インタプリタへのリンクは便利でしょう...また、UTF-16を使用して86バイト?
ピーターテイラー14年

@PeterTaylor:ありがとう、通訳へのリンクを記事に追加しました。はい、43 BMP文字はUTF-16で86バイトに変換されます。
ティムウィ14年

5

k(83)

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

繰り返しをかなり簡単に実装するだけなので、これはおそらくさらにゴルフすることができます。

基本的な進化関数、{x,,(,/((x+:i)#,@[y@&w;(i:~~#y)#0;-1+]),y@&~w:&\~y<*y;1_y)@~*y}は65文字で、ワームが死んだときに年齢の増分を停止するためにいくつかのトリックを使用します。ラッパーは、単一の整数の入力をリストに強制し、入力を反転し(表記とは逆のワームに関して繰り返しを記述する方が短い)、フィックスポイントを要求し、出力として年齢を選択し、結果を調整します。最後の世代のオーバーシュートを考慮して。

強制と反転を手動で行うと、80({-1+*({x,,(,/((x+:i)#,@[y@&w;(i:~~#y)#0;-1+]),y@&~w:&\~y<*y;1_y)@~*y}.)/(1;x)})に低下します。

いくつかの例:

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

残念ながら、非常に低速で、64ビット整数に制限されており、おそらくメモリ効率があまり高くないため、非常に理論的な意味を除いて、おそらくLargest Number Printableにはあまり使用されません。

特に、worm 2 1そしてworm 3ちょうど解約します(そして'wsfull、私がそれらを続けさせたらおそらく(メモリ不足)を投げるでしょう)。


このオンラインインタープリターを使用してプログラムを実行しようとしましたが、出力は表示されません。(拡張子が.kのテキストファイルを送信すると、Kインタープリターが呼び出されます。)出力をstdoutに送信するために何が行われるかを知っていますか?
解像度14年

k3のオープンソースクローンであるkonaを実行しているようです。私のコードはk4で書かれており、k3との互換性はほとんどありません。kx.com/software-download.phpでq / k4の期間限定無料コピーを入手できます。それができたら、REPLを起動して` to switch from q`をk入力し、コードを貼り付けます。または、.k拡張子を付けてファイルにコードを保存し、インタープリターに読み込むこともできます。
アーロンデイヴィス14年

2

APL(Dyalog Unicode)、52 バイトSBCS

@ngnと@Adámのおかげで7バイト節約されました。

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

オンラインでお試しください!

説明:

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がこれに対して本当にきれいなソリューションを持っていると考えました。それは配列ベースの言語ではありませんか?
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}

使用法:

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バイト

#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);}

オンラインでお試しください!

私はパーティーに非常に遅れていることを知っていますが、リンクリストの実装を必要とするCでこれを試してみると思いました。すべての識別子を単一の文字に変更する以外、実際にはまったくゴルフではありませんが、機能します!

全体として、これが私がこれまでに書いた3番目のC / C ++プログラムであることを考えると、私はかなり満足しています。


リンクされたリストが本当に必要ですか?配列を割り当てるだけではどうですか?これはコードゴルフであるため、完了時にわざわざ解放する必要はありません。あなたは可能性があるとしても、コールスタック(わからない)上でそれらを格納するための方法を見つけることができます。
dfeuer

また、メイン関数は必要ありません。ワームを引数として受け取り、その寿命を返す関数を記述するだけです。ワームは、配列とその長さ、または負の数で終わる配列の場合があります。
dfeuer

1

Haskell、84バイト

(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

オンラインでお試しください!

2バイトの@xnorに感謝します。

一般的な増分を除外する良い方法があるはずだと思うが、私はまだ短いものを見つけていない。


1
二つの小さなgolfs:空のリストケース秒をチェックして、シフトn1でダウン
XNOR

私はまた(n+1)!、二度書かない方法があるべきだと思いますが、私の試みは結びついています。
xnor


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.