Життя хробака


28

Умови

Черв'як є будь-яким списком невід'ємних цілих чисел, а його правий (тобто останній ) елемент називається головою . Якщо в голові немає 0, у черв'яка є активний сегмент, що складається з найдовшого суміжного блоку елементів, що включає голову і має всі її елементи принаймні такі ж великі, як і голова . Зменшується активний сегмент є активним сегментом з головою зменшується на 1. Наприклад, хробак 3 1 2 3 2має активний сегмент 2 3 2, і відновлений активний сегмент 2 3 1.

Правила еволюції

Черв'як розвивається поетапно так:

На кроці t (= 1, 2, 3, ...),
    якщо заголовок дорівнює 0: видаліть голівку
    іншим: замініть активний сегмент на t + 1 об'єднані копії зменшеного активного сегмента.

Факт : Будь-який черв'як врешті-решт перетворюється на порожній список , і кількість кроків для цього - це тривалість життя черв'яка .

(Докладні відомості можна знайти в «Принципі черв'яка» , статті Л.Д. Беклемішева. Використання «списку» для позначення кінцевої послідовності, а «голова» для позначення останнього елемента взято з цього документу - це не слід плутати із загальним використанням для списків як абстрактного типу даних , де голова зазвичай означає перший елемент.)

Приклади (активний сегмент у дужках)

Черв'як: 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) > Г.


Code Golf Challenge

Напишіть найкоротшу можливу функціональну підпрограму з такою поведінкою:

Введення : Будь-який глист.
Вихід : Термін експлуатації хробака.

Розмір коду вимірюється в байтах.


Ось приклад (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) приблизно відповідає функції Гудштейна . Так що, якщо це може бути golfed нижче 100 байт, він цілком може дати виграшну відповідь на саме велика кількість друку питання . (Для цього відповідь, темп зростання може бути значно прискорений, завжди запускаючи лічильник кроків на n - те саме значення, що і черв'як [n] - замість того, щоб запускати його з 0.)


Мене бентежить ваш код. Ви сказали, що голова - це крайній правий елемент, але у прикладі Python ви розглядаєте голову як a, 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 - Якщо перефразовувати Харві Фрідмана, числа, отримані від функцій на рівні ε_0 у швидко зростаючій ієрархії (наприклад, життя черв'яків), є абсолютно НЕВІДОМНИМ порівняно з TREE (3) .
res

Відповіді:


15

GolfScript ( 56 54 символи)

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

Демонстрація в Інтернеті

Я думаю, що ключовим трюком тут є, мабуть, збереження хробака у зворотному порядку. Це означає, що знайти компактну довжину активного сегмента досить компактно: .0+.({<}+??(де 0додається як оберіг для того, щоб ми знайшли елемент менший за голову).


Як осторонь, деякий аналіз тривалості хробака. Я позначу хробака age, head tail(тобто у зворотному порядку з позначення питання), використовуючи показники, щоб вказати на повторення в голові та хвості: наприклад, 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, яке раніше не торкалося, оскільки воно ніколи не може скласти частину активного сегмента.

За допомогою цих двох леммат ми можемо вивчити кілька простих активних сегментів.

для 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). Ми бачимо, що 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

і я дійсно можу почати розуміти, чому ця функція так шалено зростає.


Дуже круто. Я думаю, що ця програма також дасть виграшну відповідь найкоротшій програмі, що закінчується, розмір виходу якої перевищує кількість Грема . (Поточний переможець має 63 байти коду Haskell.) Наприклад, у 55 байт щось подібне (оскільки я схильний до синтаксичних помилок) 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

Я не бачив, щоб ви там нічого не публікували, тому я пішов вперед і опублікував модифікацію цього коду, як я вважаю, що до цього часу є виграшною відповіддю - припускаючи, що *і ^не використовуються як арифметичні оператори множення і експоненціювати. Звичайно, якщо ви хочете подати там свою (без сумніву, вищу) відповідь, я із задоволенням видалю свою.
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.
Пітер Тейлор

А, це не так. Він просто працює на тестових випадках, оскільки у них є лише активні паліндромні сегменти.
Пітер Тейлор

Дякуємо за пораду про гольф, @PeterTaylor. Також хороший улов на відсутньому другому реверсі. Я це додав. Спробую переписати це іншим способом, не використовуючи зворотній пізніше. Я впевнений, що зможу перенести elseпункт до одного рядка, а потім поміняти його if..else..endна потрійну заяву. Я можу також використати лямбда, щоб зберегти кілька символів, я думаю.
OI

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
Посилання на перекладача було б корисно ... Також 86 байт, використовуючи UTF-16?
Пітер Тейлор

@PeterTaylor: Спасибі, додав посилання на перекладач до статті. І так, 43 символи BMP в UTF-16 перекладають на 86 байт.
Тімві

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. Мій код написаний у k4 і навряд чи може бути сумісним з k3. Ви можете отримати обмежену в часі безкоштовну копію q / k4 за адресою kx.com/software-download.php ; як тільки це у вас є, запустіть REPL, введіть ` to switch from q` до kі вставте мій код. Як варіант, ви можете зберегти мій код у файлі з .kрозширенням і завантажити його в інтерпретатор.
Аарон Девіс

2

APL (Dyalog Unicode) , 52 байти SBCS

Збережено 7 байт завдяки @ngn та @ Adám.

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

К, 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, що вимагає реалізації пов'язаного списку. Це зовсім не гольф, окрім зміни всіх ідентифікаторів на одиночні символи, але він працює!

Загалом, я дуже радий, враховуючи, що це третя програма 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

Спробуйте в Інтернеті!

Дякуємо @xnor за два байти.

Я відчуваю, що повинен бути хороший спосіб визначити загальний приріст, але я ще не знайшов короткого.


1
Два невеликих гольфа : перевірте справу порожнього списку вдруге і змініть nна 1.
xnor

Я також думаю, що має бути спосіб не писати (n+1)!двічі, але моя спроба лише зв'язалася.
xnor


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.