웜의 수명


28

자귀

웜은 음이 아닌 정수의 목록이며, 그 오른쪽 (즉, 마지막 ) 요소는라고 머리 . 헤드가 0이 아닌 경우, 웜은 헤드를 포함하고 적어도 헤드만큼 큰 모든 요소를 ​​갖는 가장 긴 연속 요소 블록 으로 구성된 활성 세그먼트를 갖습니다 . 환원 활성 부분은 예를 들면 1만큼 감소 헤드와 유효 구간이며, 웜이 3 1 2 3 2활성 부분을 가지고 2 3 2, 환원 활성 부분이다 2 3 1.

진화의 규칙

웜은 다음과 같이 단계별로 발전합니다.

단계 t (= 1, 2, 3, ...)에서
    , 헤드가 0 인 경우 : 헤드를 삭제하고
    그렇지 않으면 : 활성 세그먼트를 축소 된 활성 세그먼트의 t + 1 연결된 사본으로 대체하십시오.

사실 : 모든 웜은 결국 빈 목록으로 진화하며, 그렇게하는 단계의 수는 웜의 수명 입니다.

(자세한 내용은 LD Beklemishev의 논문 인 The Worm Principle 에서 찾을 수 있습니다 . 유한 순서를 의미하는 "list"와 마지막 요소 를 의미하는 "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]은 이미 그레이엄의 수인 G 를 훨씬 능가하는 수명을 가지고 있습니다 .

f ω ω (2) = f ω 2 (2) = f ω2 (2) = f ω + 2 (2) = f ω + 1 (f ω + 1 (2)) >> f ω + 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


NB : t (n)이 웜 [n]의 수명 인 경우, t (n)의 성장률은 대략 Goodstein 함수 의 성장률입니다 . 따라서 이것이 100 바이트 이하로 골프를 칠 수 있다면 최대 인쇄 가능 질문에 대한 답을 얻을 수 있습니다 . (해답을 위해 스텝 카운터를 항상 0에서 시작하는 대신 웜 [n]과 동일한 값인 n에서 시작하여 성장 속도를 크게 가속화 할 수 있습니다.)


나는 당신의 코드에 혼란스러워합니다. 당신은 head가 가장 오른쪽 요소 라고 말 했지만 파이썬 예제에서는 head w[0]를 그 목록의 가장 왼쪽 요소 인 것으로 취급합니까?

@LegoStormtroopr 목록을 왼쪽과 오른쪽으로 생각할 수 있습니다. 첫 번째와 마지막을 고려하면 초기 문자열을 읽을 때 가장 오른쪽에서 첫 번째 또는 마지막으로 매핑 할 수 있습니다. 이는 질문의 일부가 아닙니다. 그러나 함수 입력도 엄격하게 정의되지 않았습니다.

@LegoStormtroopr-좋은 캐치; 입력 웜을 뒤집기 위해 줄을 추가하여 코드를 수정했습니다. 입력 웜은 실제로 머리가 오른쪽에 있어야합니다 (예 : 목록 w의 마지막 요소). 프로그램이 리버스 웜에서 작동하는 것은 효율성을위한 것입니다.
res

올바른 얻기 대답 에 대한 2 1적절한 시간에 질문하는 너무 많은 수 있습니다,하지만 유용한 테스트는 순서가 시작해야 함을 (2 1), 2 0 2 0, 2 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머리와 꼬리의 반복을 나타내는 지수를 사용하여 웜을 (즉, 질문의 표기법과 반대 순서로) 표시합니다. 예 : 2^3is 2 2 2.

Lemma : 모든 활성 세그먼트 xsf_xs대해로 age, xs 0 tail변환 하는 기능이 f_xs(age), tail있습니다.

증거 : 활성 세그먼트에는을 포함 할 수 없으므로 0테일이 테일과 무관하기 때문에 모든 것이 삭제 될 때까지의 나이는 테일의 함수입니다 xs.

렘마 : 활성 세그먼트 xs에 대해 웜 age, xs은 나이에 죽습니다 f_xs(age) - 1.

증명 : 이전의 정리로으로 age, xs 0변환합니다 f_xs(age), []. 마지막 단계는 해당 0세그먼트를 삭제하는 것입니다.이 세그먼트는 활성 세그먼트의 일부를 절대로 형성 할 수 없으므로 이전에 건드리지 않았습니다.

이 두 가지 정리를 통해 간단한 활동 세그먼트를 연구 할 수 있습니다.

를 들어 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 2( 2 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 바이트가있다.) 예는, 55 바이트에서, 같은 (I 구문 오류 경향이있어 이후가) 9{-1%0\{\)\.0={.0+.({<}+??\((\+.@<2$*\+}{(;}if.}do;}:L~멀리 그레이엄의 수를 초과하는 웜의 수명 [9], 계산 - 그리고 될 수 있습니다 더 골프.
res

9

GolfScript, 69 62 자

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

이 함수 C는 스택에서 웜을 예상하여 결과로 대체합니다.

예 :

> [1 1]
19

> [2]
51

> [1 1 0]
51

환상적인! 확실히 "최대 숫자 인쇄 가능" 질문에 대한 확실한 승자를 제공하기 위해이 비트를 약간 수정할 수 있습니다 .
해상도

나는 당신이 거기에 아무것도 게시하지 않는 것을 보았습니다. 그래서 나는 이 코드 를 내가 지금까지 승리 한 답변이라고 생각하는 것으로 수정했습니다 - *^의 곱셈 연산자로 사용되고 있다고 가정 그리고 지수. 확실히, 당신이 거기에 자신의 (의심 할 여지없이 우수한) 답변을 제출하고 싶다면, 나는 행복하게 내 것을 제거 할 것입니다.
res

7

루비 — 131 자

나는 이것이 위의 GolfScript 솔루션과 경쟁 할 수 없다는 것을 알고 있으며 이것이 점수 또는 더 많은 문자를 줄일 수 있다고 확신하지만 솔직히 문제를 해결할 수있게되어 기쁩니다. 큰 퍼즐!

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==0로 다듬을 수 있습니다 if foo<1. 그것은 당신에게 하나의 문자를 저장할 수 있습니다.
피터 테일러

우연히도, 이것이 초없이 작동한다는 것은 매력적입니다 reverse.
피터 테일러

아, 그렇지 않습니다. 그것은 단지 palindromic active segment만을 가지고 있기 때문에 테스트 케이스에서 작동합니다.
피터 테일러

골프 팁 @PeterTaylor에게 감사합니다. 또한 누락 된 두 번째 리버스를 잘 잡습니다. 나는 그것을 추가했다. 나는 나중에 리버스를 사용하지 않고 다른 방법으로 다시 쓰려고 노력할 것이다. else절을 한 줄로 if..else..end가져간 다음 삼항 문 을 바꿀 수 있다고 확신 합니다. 람다를 사용하여 문자 몇 개를 구할 수도 있다고 생각합니다.
OI

6

자르기 (43 자)

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

이것은 입력을 공백으로 구분 된 목록으로 예상합니다. 이 출력에 대한 정답 1 12만에 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 바이트?
피터 테일러

@PeterTaylor : 감사합니다. 기사에 대한 통역사 링크가 추가되었습니다. 그렇습니다. 43 개의 BMP 문자가 UTF-16에서 86 바이트로 변환됩니다.
Timwi

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 비트 정수로 제한되며 특히 메모리 효율적이지 않기 때문에 가장 큰 숫자 인쇄 가능 에는별로 사용 되지 않을 것입니다.

특히, worm 2 1그리고 worm 3그냥 떨리십시오 (그리고 'wsfull내가 계속 내버려두면 아마도 (메모리에서 던져 질 것입니다 )).


이 온라인 인터프리터로 프로그램을 실행하려고 시도했지만 출력이 표시되지 않습니다. (확장명이 .k 인 텍스트 파일을 제출하면 K 인터프리터가 호출됩니다.) 출력을 stdout으로 전송하기 위해 수행 할 수있는 작업을 알고 있습니까?
res

k3의 오픈 소스 클론 인 kona를 실행중인 것 같습니다. 내 코드는 k4로 작성되었으며 k3과 호환되지 않을 수 있습니다. kx.com/software-download.php 에서 q / k4의 시간 제한 무료 사본을 얻을 수 있습니다 . 그런 다음 REPL을 시작하고 ` to switch from q` to를 입력 k하고 코드를 붙여 넣습니다. 또는 .k확장명을 가진 파일에 코드를 저장 하여 인터프리터에로드 할 수 있습니다.
Aaron Davies

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

스칼라, 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

하스켈 , 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
두 개의 작은 골프 : 빈 목록 케이스를 두 번째로 확인하고 n1 씩 줄입니다.
xnor

또한 (n+1)!두 번 쓰지 않는 방법이 있어야한다고 생각 하지만 내 시도 는 묶여 있습니다.
xnor


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.