Электроны подпрыгивают в проводе

46

Представьте себе «провод» с nпробелами. Представьте далее, что в этом проводе есть «электроны». Эти электроны живут только одну единицу времени. Любые пространства в проводе, которые прилегают к одному электрону, становятся электроном. В терминологии Game of Life это так B1/S.

Например, это провод длиной 10 с периодом 62.

введите описание изображения здесь

правила

  • Входные данные, nэто одно положительное целое число.
  • Выходными данными должно быть одно целое число, обозначающее период провода длиной n.
  • Начальное состояние - один электрон на одном конце провода.
  • Период не обязательно включает начальное состояние. Некоторые длины никогда не возвращаются в исходное состояние, но все они периодические.
  • Статический провод (т.е. без электронов) имеет период 1.
  • Граничные условия не являются периодическими. То есть провод никоим образом не является тороидальным.

Контрольные примеры

Отдельное спасибо orlp за создание этого списка. (Я проверил это до n = 27.)

1 1
2 2
3 1
4 6
5 4
6 14
7 1
8 14
9 12
10 62
11 8
12 126
13 28
14 30
15 1
16 30
17 28
18 1022
19 24
20 126
21 124
22 4094
23 16
24 2046
25 252
26 1022
27 56
28 32766
29 60
30 62
31 1
32 62
33 60
34 8190
35 56
36 174762
37 2044
38 8190
39 48
40 2046
41 252
42 254
43 248
44 8190
45 8188

Вы можете увидеть тестовые случаи для n = 2 до 21 здесь с моим симулятором Game-of-Life-esque: Variations of Life .


РЕДАКТИРОВАТЬ: последовательность здесь была опубликована как A268754 !

El'ndia Starman
источник
все они периодические, а период ограничен сверху 2^n-1, потому что это число возможных ненулевых состояний «провода»
Луис Мендо
@LuisMendo: На самом деле, верхняя граница меньше, потому что электроны никогда не соседствуют. Точно, насколько меньше, я не знаю.
El'endia Starman
The period does not necessarily include the starting state. Some lengths never return to the starting state, but all of them are periodic.У вас есть пример?
edc65
@ edc65: провод длиной 5 - самый маленький пример.
El'endia Starman
1
Более сильно, электроны чередуются между нечетным и четным положением, поэтому период составляет не более 2 ^ (n / 2 + 1).
xnor

Ответы:

10

Python 2, 148 142 87 байт

n=input()
p=l=1
t=1
h=2
while t!=h:
 if p==l:t,l,p=h,0,p*2
 h=h/2^h*2%2**n;l+=1
print l

Использует алгоритм обнаружения цикла Брента и, таким образом, на самом деле работает быстро.


Я также написал анимацию на Python (обе работы 2 и 3). Это должно pygletбежать. Вы можете просмотреть анимацию, запустив:

python -m pip install --user pyglet
curl -s https://gist.githubusercontent.com/orlp/f32d158130259cbae0b0/raw/ | python

(Не стесняйтесь загружать суть и проверять код перед запуском.) Вы можете нажимать кнопки + и - для увеличения / уменьшения визуализируемого n .


И, наконец, для тех, кто заинтересован в дальнейшем изучении этой числовой последовательности, вот читаемая версия (она использовалась для генерации тестовых случаев выше):

# Brent's cycle detection, modified from wikipedia.
def electron_period(n):
    wire_mask = (1 << n) - 1
    power = lam = 1
    tortoise, hare = 1, 2
    while tortoise != hare:
        if power == lam:
            tortoise = hare
            power *= 2
            lam = 0
        hare = ((hare << 1) ^ (hare >> 1)) & wire_mask
        lam += 1
    return lam
orlp
источник
Я знаю, что прошло больше года, но мне интересно, если бы использование HashLife ускорило бы его вообще
только для ASCII
7

Mathematica, 127 байт

p@n_:=Tr[#2-#]&@@Position[#,Last@#]&@NestWhileList[1~Table~n~ArrayPad~1*18~CellularAutomaton~#&,{1}~ArrayPad~{1,n},Unequal,All]

объяснение

Правило 18 :

{0,0,0} -> 0
{0,0,1} -> 1
{0,1,0} -> 0
{0,1,1} -> 0
{1,0,0} -> 1
{1,0,1} -> 0
{1,1,0} -> 0
{1,1,1} -> 0

Контрольные примеры

p/@Range[10]
(* {1,2,1,6,4,14,1,14,12,62} *)
njpipeorgan
источник
7

Python 2, 68 байт

f=lambda n,k=1,l=[]:k in l and-~l.index(k)or f(n,k/2^k*2%2**n,[k]+l)

Обнаружение цикла может быть лучше, но итеративный шаг хорош.

k -> k/2^k*2%2**n

Представляя массив в виде двоичного числа k, обновление можно выполнить, взяв XOR со kсмещением на одну влево /2и одну вправо *2, а затем обрезая до nбайтов как %2**n.

XNOR
источник
4

Python 3 2, 134 121 118 байт

Q=input()
h=[]
n=[0,1]+Q*[0]
while n not in h:h+=[n];n=[0]+[n[d]^n[d+2] for d in range(Q)]+[0]
print len(h)-h.index(n)

В основном так же, как мой ответ Pyth , но несколько адаптировал его из-за отсутствия определенных встроенных функций в Python.

Безголовая версия:

length = input()
history = []
new = [0] + [1] + length*[0]
while new not in history:
    history += [new]
    new = [0] + [new[cell]^new[cell+2] for cell in range(length)] + [0]
print len(history) - history.index(new)
busukxuan
источник
4

Pyth, 39 36 байт

L++Zmx@bd@bhhdQZ-lJ.uyN.[,Z1ZQ)xJyeJ

Использует функцию «накопленной фиксированной точки» для итерации до того, как конфигурация повторяется, и возвращает все промежуточные конфигурации в виде списка списков. Это работает, потому что правила являются детерминированными, а конфигурация следующего поколения является функцией текущей конфигурации. Это означает, что как только та же конфигурация появится снова, автоматы завершили цикл.

После достижения этого (последняя итерация цикла) она вызывает функцию следующего поколения в последний раз в последнем элементе списка «истории», чтобы получить следующую конфигурацию (которая является начальной конфигурацией цикла), и найти свой указатель в истории. Теперь период - это просто длина (1 + индекс окончания цикла) минус индекс начала цикла.

В питоническом псевдокоде:

                  Z = 0
                  Q = eval(input())
L                 def y(b):                # generates next-gen from current(param)
  ++Zm                return [Z] + map(    # adds head zero padding
    x@bd@bhhd             lambda d: b[d] ^ b[1+ 1+ d],  # xor the states of adjacent cells
    Q                     range(Q))        # implicit range in map
    Z                     + [Z]            # adds end zero padding
-lJ.uyN.[,Z1ZQ)   J = repeatTilRecur(lambda N,Y:y(N), padRight([Z,1],Z,Q)); print( len(J) -
                  # N:value; Y:iteration count
  JxJyeJ              J.index( y( J[-1] ) ) )

Набор тестов занимает слишком много времени, чтобы сервер убил его, поэтому вам нужно будет использовать обычную программу и протестировать ее одну за другой, или установить Pyth (если вы этого не сделали) и использовать скрипт для его тестирования.

busukxuan
источник
4

Желе, 19 18 17 байт

H^Ḥ%®
2*©Ç‘СUµiḢ

Этот код вычисляет первые 2 n состояния, поэтому он не особенно быстрый и не эффективен для памяти ...

Попробуйте онлайн! или проверьте первые 16 тестовых случаев .

Альтернативная версия, 13 байт (не конкурирует)

Версии Jelly, перенесшие эту проблему, имеют встроенное обнаружение петель, что делает решение более коротким и эффективным.

H^Ḥ%®
2*©ÇÐḶL

Это легко обрабатывает последний контрольный пример. Попробуйте онлайн!

Как это устроено

2*©Ç‘СUµiḢ    Main link. Input: n (integer)

2*             Compute 2 ** n.
  ©            Store the result in the register.
     С        Do the following:
   Ç             Apply the helper link, which updates the state, ...
    ‘            2 ** n + 1 times.
               Collect all 2 ** n + 2 intermediate results in a list.
       U       Upend; reverse the list of results.

        µ      Begin a new, monadic chain. Argument: R (list of results)
          Ḣ    Yield and remove the first element of R (final state).
         i     Find its first index in the remainder or R.
               This is the length of the loop.

H^Ḥ%®        Helper link. Argument: s (state, integer)

H            Halve s. This yields a float, but ^ will cast to integer.
  Ḥ          Double s.
 ^           Compute (s ÷ 2) ^ (s × 2).
    ®        Retrieve the value stored in the register (2 ** n).
   %         Compute ((s ÷ 2) ^ (s × 2)) % (2 ** n).

Обратите внимание, что вспомогательная ссылка применяется к 2 n в первой итерации, которая не кодирует допустимое состояние. Однако ((2 n ÷ 2) ^ (2 n × 2))% 2 n = (2 n - 1 + 2 n + 1 )% 2 n = 2 n - 1 , что является одним из возможных начальных состояний.

Поскольку мы выполняем цикл 2 n + 1 раз, мы гарантированно сталкиваемся с состоянием дважды, что делает обнаружение цикла успешным.

Деннис
источник
3

CJam, 41 34 31 27 25 байт

Спасибо Деннису за сохранение 3 байта. Заимствование идеи из его ответа желе спасло еще 4.

2ri#_){__4*^2/W$%}*]W%(#)

Проверьте это здесь.

объяснение

Я представляю провод просто как целое число (чьи биты указывают позиции электронов) вместо того, чтобы использовать фактический список битов. Состояние обновляется с помощью довольно простых побитовых вычислений.

Чтобы найти период, мы собираем все промежуточные результаты в стеке, запускаем симуляцию для 2 n-1 +1 шагов, а затем определяем период как количество элементов с момента последнего появления конечного состояния (плюс 1).

Вот разбивка кода:

2ri#   e# Compute 2^n. This has a 1 in the n+1-th bit and zeroes below it. This is
       e# itself not a valid state but will be turned into 2^(n-1) by the first
       e# update.
_)     e# Duplicate and increment to get number of steps to simulate.
{      e# Repeat that many times...
  __   e#   Duplicate the last state twice.
  4*   e#   Multiply by 4, shifting all bits to the left by two positions.
  ^    e#   XOR - we only keep keep those cells where we have exactly one 1-bit
       e#   between both copies, i.e. those that neighboured a single electron
       e#   but shifted up by one position. We don't need handle the survival rule
       e#   explicitly, since electrons can never be adjacent in the first place.
  2/   e#   Divide by 2 shifting all bits back to the right again.
  W$   e#   Copy the initial number 2^n.
  %    e#   Modulo - this simply sets the first bit to 0.
}*
]      e# Wrap all states in an array.
W%     e# Reverse it.
(      e# Pull off the latest state.
#      e# Find its position in the remainder of the array.
)      e# Increment.
Мартин Эндер
источник
2

JavaScript (ES6) 99 104

n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

Контрольная работа

f = n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

console.log = x => O.textContent += x + '\n';

;[...Array(45)].map((_, i) => console.log(++i + ' ' + f(i)))
<pre id=O></pre>

edc65
источник
2

Haskell, 170 байт

x!pдает элемент с индексом p, если в границах, иначе 0. nвычисляет следующий шаг. g iдает iшаг. c xдает период, если начинается с x. fоборачивает все это вместе.

n x|l<-length x-1=[mod(x!(p-1)+x!(p+1))2|p<-[0..l],let y!q|q<0=0|q>=l=0|1<2=y!!p]
c x=[i-j|i<-[1..],j<-[0..i-1],let g k=iterate n x!!k,g i==g j]!!0
f n=c$1:map(*0)[2..n]

(Примечание: отправлено с телефона, который имеет интерпретатор объятий, который не является полнофункциональным, поэтому может иметь опечатки.)

Майкл Кляйн
источник
2

MATL , 38 37 36 35 байт

1Oi(`t0Y)5BX+8L)1=vt6#Xut0)=fdt?w}A

При этом используется цикл, который продолжает вычислять новые состояния, пока новое состояние не станет равным любому из предыдущих. Каждое состояние - это вектор нулей и единиц. Эти векторы хранятся в виде строк растущего двумерного массива.

Вычисление каждого нового состояния выполняется путем свертки текущего состояния с последовательностью [1,0,1], сохранения только центральной части и установки 0любой записи, которая не является 1.

РЕДАКТИРОВАТЬ (13 мая 2016 г.) Код в следующей ссылке был слегка изменен в соответствии с изменениями, внесенными в язык после написания этого ответа

Попробуйте онлайн!

1Oi(            % create initial vector [1,0,0,...,0], with size equal to input
`               % do...while loop
  t0Y)          %   duplicate. Get last row of array: most recent vector
  5BX+8L)       %   compute new vector by convolving the most recent one
                %   with [1,0,1] and keeping only the central part
  1=            %   set ones to 1, rest to 0
  v             %   append to 2D array
  t6#Xu         %   compute vector of unique numeric labels, so that equal rows
  t0)=f         %   indices of entries whose value equals that of the last entry.
                %   This will contain the index of the last entry and possibly
                %   another index, in which case we've found a repetition
  d             %   this will either be empty (which is falsy) or contain the
                %   period, which is a nonzero number (and thus truthy)
  t?            %   duplicate. If non-empty (and nonzero)
    w           %     swap to put the 2D-array at the top of the stack. This is
                %     falsy, because it contains at least one zero, even in the
                %     n=1 case (the array is initiallized to 0 in that case)
                %     So the loop will terminate, with the period left on the stack
  }             %   else
    A           %     this transforms the empty array at the top of the stack
                %     into a true value, so that the loop will continue
                %   implicitly end if
                % implicitly end loop
                % implicitly display stack contents (period)
Луис Мендо
источник
1

Perl 6, 81 байт

{my@h=my$w=2;@h.push($w=$w/2+^$w*2%2**$_)while 2>@h.grep($w);[R-] @h.grep($w,:k)}

Немного расширился и расклеился

-> $n {
    my @history = my $wire = 2;
    while 2 > @history.grep($wire) {
        @history.push($wire = $wire/2 +^ $wire*2 % 2**$n)
    }
    [R-] @history.grep($wire,:k)
}

Немного объяснения:

  • [op]сокращает список с помощью оп. Например [+] @listбудет сумма@list
  • Rэто метаоперация, которая переворачивает аргументы, данные оператору Например 1 R- 3приведу в 2.
Клавиатурный
источник
1

C ++, 211 байт

Golfed

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);int main() {int p,l;for(scanf("%d",&p);p--;m.set(p));
for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;return !printf("%d",l);}

С добавленным пробелом для удобства чтения

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);
int main() {    
    int p,l;
    for(scanf("%d",&p);p--;m.set(p));
    for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;    
    return !printf("%d",l);
}

Хорошая практика для набора битов C ++; и хорошее образование, узнающее об алгоритме обнаружения цикла Брента (как используется @orlp)

белый дельфин
источник
0

Pyth, 95 байт

J.[ZQ[1)K_1=bYW<K0=NY aN?hJZ?htJ1ZFTr1tlJ aN?@JTZ?x@JhT@JtT1Z) aN?eJZ?@J_2 1Z=JN=KxbJ abJ;-tlbK

Вы можете попробовать это здесь .

Rhyzomatic
источник
0

Рубин, 72 байта

Анонимная функция.

->n{s=[w=1];c=p
(j=s.index w=w*2%2**n^w/2
j ?c=s.size-j:s<<w)while !c
c}
Значение чернил
источник