计数多带


18

多条带是符合以下规则的多氨基酸的子集:

  • 每块由1个或多个单元组成
  • 没有一个单元可以有两个以上的邻居
  • 电池不应围成一个洞

当自由多胺基不是另一个(可以拾取和翻转)的刚性转换(平移,旋转,反射或滑行反射)时,它们是不同的。平移,旋转,反射或滑动以反映自由多米诺骨牌不会改变其形状(Wikipedia

例如,有30个免费的七边形带(长度为7的多带)。这些都是14x15的网格。

七条纹

图片来源:Miroslav Vicher

目标

编写一个程序/函数,将正整数n作为输入并枚举不同的自由多n带。

  • n = 1-> 1(一个正方形)

  • n = 2-> 1(只有一个可能的由2个正方形组成的2折带)

  • n = 3-> 2(一个由3个正方形连接成一条直线,另一个为L形)

  • n = 4-> 3(一个直线,一个L形和一个Z形)

  • 。。。

测试用例:

n   polystrips

1   1
2   1
3   2
4   3
5   7
6   13
7   30
8   64
9   150
10  338
11  794
12  1836
13  4313
14  10067
15  23621

计分

这是,因此代码越短越好。我将非常感谢对该算法和代码的详细说明。

J中的部分参考实现

我决定以“矢量”格式描述每个片段,而我只需要n-2个块来描述一个n-polystrip片段(只有1个2-polystrip,并且将其显式返回)。这些块描述了相对方向:0-无变化;1-向左转;2-向右转。哪个方向开始并不重要,而只是指示下一个单元的放置位置。可以有任意数量的连续0,但是1和2始终是单个。此实现是局部的,因为它不考虑孔的问题-n> 6的解决方案也计算有孔的部分。

Try it online!


1
相关的OEIS。(但不排除漏洞。)
Martin Ender '18

@ Martin Ender谢谢,我不知道。
Galen Ivanov '18

2
可以肯定的是,我假设是否填充了一个3x3的网格(除了中心和一个角也算作一个孔(101010在示例符号中))?
Ton Hospel '18

@Ton Hospel是的,的确是-这是唯一带有孔的七边形碎片。
Galen Ivanov '18

1
SE
Jonah

Answers:


12

Python 3中480个 433 406 364 309 299 295字节

看起来是开始我的PPCG事业的好时机(或没有?)。

def C(s):
 S,*a={''},0,1;n=d=r=1
 for c in s:d=c*d*1jor d;n+=d;a+=n,;r*=not{n}&S;x,*a=a;S|={x+t+u*1jfor t in A for u in A}
 return r
from itertools import*;A=-1,0,1;n,y=int(input())-2,0;x={*filter(C,product(*[A]*n))}
while x:s=x.pop();S=*(-u for u in s),;x-={s[::-1],S,S[::-1]}-{s};y+=1
print(y)

在线尝试!

编辑:

  • 内联DX,并在一些高尔夫球场上进行了一些调整。
  • 应用更多的技巧,主要是与集合相关的技巧。
  • 更改为程序形式,并更改为使用复数而不是任意数m。(复数确实是一个强大的功能,但经常被忽略,它是根据xnor的解决方案改编而成的,以应对另一个挑战
  • LFR字符串表示形式更改为-1,0,1元组,并牺牲了执行时间以减少疯狂的字节减少量(!)。现在从理论上讲解决方案是正确的,但是在输出结果15之前会超时。
  • 多亏了乔纳森·弗雷奇(Jonathan Frech),单行循环了,然后我找到了更好的计算方法r。最终不到300个字节!!!
  • 令人惊讶的是,它1j可以坚持使用其他任何东西而不会混淆解析器(-2B),并且not具有极低的优先级(-2B)。

过时的版本(480字节):

def C(s):
 m=999;a=[0,1];n=d=1
 D={'F':{},'L':{1:m,m:-1,-1:-m,-m:1},'R':{1:-m,-m:-1,-1:m,m:1}}
 X=lambda x:{x+~m,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x-~m}
 for c in s:
  d=D[c].get(d,d);n+=d;a+=n,
  if n in set().union(*map(X,a[:-3])):return 0
 return 1
def f(n):
 if n<3:return 1
 x={*'LF'}
 for _ in range(3,n):x={s+c for s in x for c in({*'LRF'}-{s[-1]})|{'F'}}
 y={*x}
 for s in x:
  if s in y:S=s.translate(str.maketrans('LR','RL'));y-={s[::-1],S,S[::-1]}-{s}
 return sum(map(C,y))

在线尝试!

带有注释的非解决方案:

t = str.maketrans('LR','RL')

# hole checking function
def check(s):
    m = 999   # (imaginary) board size enough to fit all generated polyominoes
    a = [0,1] # previous path
    n = 1     # current cell
    d = 1     # current direction
    # dict for direction change
    D = {'F':{}, 'L':{1:m, m:-1, -1:-m, -m:1}, 'R':{1:-m, -m:-1, -1:m, m:1}}
    # used to 'blur' all cells in path into 3x3
    X = lambda x: {x-m-1,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x+m+1}
    for c in s:
        d = D[c].get(d,d) # change direction
        n += d            # move current cell
        # the polyomino has a hole if the current cell touches previous cells (including diagonally; thus the blurring function)
        if n in set().union(*map(X,a[:-2])): return False
        a.append(n)       # add current cell to the path
    return True

# main function
def f(n):
    if n < 3: return 1
    x = {*'LF'}
    # generate all polystrips using the notation similar to the reference
    for _ in range(3, n): x = {s+c for s in x for c in ({*'LRF'}-{s[-1]})|{'F'}}
    y = {*x}
    # remove duplicates (mirror, head-to-tail, mirror of head-to-tail) but retain self
    for s in x:
        if s in y:
            S = s.translate(t)
            y -= {s[::-1], S, S[::-1]} - {s}
    # finally filter out holey ones
    return sum(map(check,y))

在线尝试!

m = 999之所以选择,是因为它花费了所有时间的指数时间,并且已经花费了大约8s的时间进行计算n = 1..15。也许可以使用99代替保存1个字节。我们不再需要它了,由于内置了复杂的数字,现在可以保证它对于任意输入大小都是正确的。


5
欢迎来到PPCG!绝对是您开始PPCG职业生涯的令人印象深刻的方法。:)
Martin Ender '18

3
欢迎使用PPCG,感谢您的解决方案!我已经放弃期望看到一个解决方案了:)
Galen Ivanov

3
看起来是开始我的PPCG事业的好时机(或没有?)好吧,对于我们大多数人甚至都不会想到的这,这是一个出乎意料的简短解决方案,即使非高尔夫版本看起来也出奇的简单,但是,嗯,也许这是开始您的PPCG事业的一种普通方法,对吧?:)
暴民埃里克(Erik the Outgolfer)

1
@Erik这句话只是个笑话:)但是,对我来说,解决方案甚至令人惊讶-我从没想到自己会将原始提交的费用减少约36%。
Bubbler


4

APL(Dyalog Unicode)70 65字节

+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳2↓⎕⍴3

在线尝试!

感谢Adám,以下代码的完整程序版本。


APL(Dyalog Unicode),70字节

{+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳3⍴⍨0⌈⍵-2}

在线尝试!

怎么运行的

上面的代码等效于以下定义:

gen←{2-,⍳3⍴⍨0⌈⍵-2}
canonicalize←{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
test←{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{+/test¨∪canonicalize¨gen⍵}

这就像Python解决方案一样工作,但是顺序不同。它generates LFR长度的-strips n-2canonicalizes各自条,需要NIQUE条,tests各自条如果它接触本身(1,如果不接触,否则为0),并总结+/布尔结果。

gen

{2-,⍳3⍴⍨0⌈⍵-2}
{            }   ⍵←input number n
        0⌈⍵-2    xmax(0, n-2)
     3⍴⍨         x copies of 3
   ,⍳            multi-dimensional indexes; x-th cartesian power of [1,2,3]
                 (`⍳` gives x-dimensional hypercube; `,` flattens it)
 2-              compute 2-k for each k in the array

 in each strip, ¯1, 0, 1 corresponds to R, F, L respectively

canonicalize

{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
{                  }   ⍵←single strip
              ⍵(-⍵)    nested array of  and its LR-flip
        (⊢,⌽¨)         concatenate their head-to-tail flips to the above
 (⊃∘⍋  )               find the index of the lexicographically smallest item
     ⊃⊢                take that item

test

{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{                                  }   ⍵←single strip
                              0j1*⍵    power of i; direction changes
                            ×\         cumulative product; directions
                        0 1,     initial position(0) and direction(1)
                      +\         cumulative sum; tile locations
 (  ⊢{           }¨,\)    test with current tile(⍺) and all tiles up to ⍺(⍵):
             ¯3↓⍵         x←⍵ with last 3 tiles removed
           ⍺-             relative position of each tile of x from 
        2≤|               test if each tile of x is at least 2 units away
      ∧/                  all(...for each tile in x)
  ∧/         all(...for each position in the strip)

-5
亚当
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.