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


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←⍺+1⋄0=⊃⍵:n∇1↓⍵⋄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=⊃⍵:n∇1↓⍵ ⍝ 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.