电子在电线上弹跳


46

想象一下有n空间的“电线” 。进一步想象一下,该导线中存在“电子”。这些电子仅生存一个时间单位。导线中恰好与一个电子相邻的任何空间都将成为电子。在“生活游戏”术语中,这是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的测试用例。


编辑:这里的序列已发布为A268754


它们都是周期性的,并且该周期的上限是2^n-1,因为这是“导线”的可能非零状态的数量
Luis Mendo

@LuisMendo:实际上,上限较小,因为电子从不相邻。确切地少了多少,我不知道。
El'endia Starman '02

The period does not necessarily include the starting state. Some lengths never return to the starting state, but all of them are periodic.你有例子吗?
edc65 '16

@ edc65:最小长度为5的电线。
El'endia Starman '02

1
更强烈地,电子在奇数和偶数位置之间交替,因此周期最多为2 ^(n / 2 + 1)。
xnor

Answers:


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

我知道已经过去了一年,但是我想知道使用HashLife是否会加快它的发展速度
ASCII码仅适用于2002年

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} *)

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,可以通过将k左移与/2右移*2,然后截断为n字节的XOR来完成更新%2**n


4

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)

4

Pyth,39 36个字节

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

使用“累积定点”功能迭代直到配置再次出现之前,然后将所有中间配置作为列表列表返回。这是可行的,因为规则是确定性的,并且下一代的配置是当前配置的函数。这意味着一旦再次出现相同的配置,自动机便完成了一个周期。

到达那个值(循环的最后一个迭代)后,它在“历史记录”列表的最后一个元素上最后一次调用次世代函数,以获得下一个配置(这是循环的开始配置),并且在历史记录中找到它的索引。现在,周期就是长度(1 +循环结束的索引)减去循环开始的索引。

在pythonic伪代码中:

                  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(如果尚未安装)并使用脚本对其进行测试。


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字节

感谢Dennis节省了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>


2

Haskell,170个字节

x!p如果在边界内,则在索引p处给出元素,否则为0。 n计算下一步。 g i给出第ith步。 c x如果以开头,则给出句号xf包裹在一起。

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

MATL38 37 36 35字节

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

这使用了一个循环,该循环不断计算新状态,直到新状态等于之前的任何状态为止。每个状态都是零和一的向量。这些向量存储为不断增长的2D阵列的行。

每个新状态的计算是通过将当前状态与序列卷积[1,0,1],仅保留中心部分并设置0为not的任何条目来完成的1

编辑(2016年5月13日)根据编写此答案后在语言中引入的更改,对以下链接中的代码进行了一些修改

在线尝试!

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]使用op减少列表。例如[+] @list将求和@list
  • R是一个元操作,可反转提供给操作的参数。例如1 R- 3将导致2。

1

C ++,211字节

打高尔夫球

#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 ++的位集的良好实践;以及关于Brent周期检测算法(@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

您可以在这里尝试。



0

Ruby,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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.