磁性雕塑


14

这是我先前在构造图时遇到的挑战的宽松延续。

背景

一位古怪的艺术家雇用您来估计他的雕塑的结构完整性。他通过拿起一堆立方体形状的磁铁,然后将它们一个个地扔进一大堆中来创作自己的艺术品。为了更好地分析他的方法,我们使用以下二维模型。我们从一个空的地板开始,然后将磁铁#放在任何整数坐标上,例如0

       |
       v
       #
===============
       0

如果将另一个磁铁放到处0,它最终会位于前一个磁铁的顶部:

       |
       v
       #
       #
===============
       0

现在,让我们在放另外一个磁铁0,然后在放一个1

        |
       #v
       ##
       #
===============
       0

如上所示,一个下落的磁铁粘在它通过的第二个磁铁上(第一个只是使它减速)。第二个磁体不必直接位于第一个磁体的下方,并且两侧的磁体仍视为一个磁体:

      #   #
      ##|##
      # v #
      ### #
      #   #
===============
       0

艺术家希望您计算最终雕塑中的最大垂直间隙,即,同一列上的两个磁体之间或磁体与其下方的地面之间的最大空白空间。在上图中,该数字将为3(在列上2)。

输入值

从左到右读取的整数列表,代表艺术家放下磁铁的坐标。您可以假设坐标满足-1024 <= i < 1024并且列表的长度最大为1024,如果有帮助的话。

输出量

最终雕塑中的最大垂直间隙。-1由于我们的雕刻家是达达主义者,因此空雕塑有缝隙,并且必须包括这种情况。

附加规则

您可以提供功能或完整程序。最短的字节数获胜,并且不允许出现标准漏洞。带有说明的代码是首选。

测试用例

[] -> -1
[0,2,1] -> 0
[0,0,0,0,0,1,-1] -> 3
[0,0,0,0,0,1,1,1,2] -> 4
[1,1,2,2,2,2,2,2,1] -> 2
[1,1,2,2,2,2,2,2,1,0,1,0] -> 2
[1,2,1,2,1,2,1,2,2,2,2,1,0] -> 3
[-1,-1,-1,1,1,1,0] -> 1
[-1,-1,-1,-1,2,2,1,1,2,2,2,1,0] -> 2
[-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,4,4,5,5,5,6] -> 6

Answers:


1

Dyalog APL,73个 70个字符

{y←⍬⋄⌈/¯1,,¯1-2-/0,x⊢⌸{y,←⌈/(1+y/⍨0=⍵),Y⊃⍨2⊃⍒Y←1 1,∪y/⍨1=⍵}¨|x-¯1↓¨,\x←⍵}

{y←⍬⋄¯1⌈⌈/,¯1-2-/¯1,⍵⊢⌸{y,←⌈/(1+y/⍨0=⍵),⊃1↓{⍵[⍒⍵]}∪y/⍨1=⍵}¨|⍵-¯1↓¨,\⍵}

First statement:
       y←⍬  initialize semi-global variable y with an empty vector
Second statement, from right to left:
         ⍵  the vector of x coordinates
       ,\⍵  concat-scan: all prefixes of ⍵ of length 1, 2, ..., ≢⍵
   ¯1↓¨,\⍵  drop the last element of each prefix, lengths are 0, 1, ..., (≢⍵)-1
|⍵-¯1↓¨,\⍵  for each x: magnitudes of differences between x and its predecessors
 {...}¨...  execute the code in parens for each item of the argument
         ⍵  is now a single vector of differences from those described above
       1=⍵  boolean mask, where are our neighbouring xs?
    y/⍨1=⍵  select the ys corresponding to our neighbouring xs
   ∪y/⍨1=⍵  unique ys
   {⍵[⍒⍵]}  sort descending
       ⊃1↓  first of one-drop, i.e. get the second element if it exists, otherwise 0
       0=⍵  which previous xs are the same as our x?
  1+y/⍨0=⍵  select the corresponding ys and add 1 to them
        ⌈/  maximum of all the ys described so far
       y,←  append to the semi-global y
            the result from {} will be identical to y
  ⍵⊢⌸{...}  a matrix of ys, grouped in rows by x (which is now in ⍵) and zero-padded
       ¯1,  prepend ¯1 to the left of each row
       2-/  differences between consecutive horizontal elements, result is a matrix
       ¯1-  negative one minus each element of the matrix
         ,  ravel the matrix (linearize it to a vector)
        ⌈/  maximum; if the vector is empty, return ¯1.8e308, a very small number
     ¯1⌈⌈/  greater of ¯1 and the ⌈/  to avoid the very small number

注意:假设为UTF-8,长度为122个字节(挑战以字节为单位)。
MtnViewMark


我很同情:我经常因为在我的golf'd Haskell中使用非ASCII字符而感到厌烦。从那时起,我就非常注意Q是否指定字符或字节数。
MtnViewMark'1

@MtnViewMark按字节计分并不意味着按UTF-8字节计分。这样做对APL来说是一种惩罚,因为它太旧了,无法将ASCII视为重要的标准。APL的字符集可轻松放入单字节代码页中,并且该代码页存在。因此,使用该代码页作为编码,每个字符都是一个字节。另一方面,如果在Haskell中使用非ASCII字符,则必须使用既包含ASCII字符又包含非ASCII字符的编码-通常为UTF-8。
Martin Ender'1

@ngn-现在已经阅读了有关此内容的大多数meta帖子,可惜事情似乎还很泥泞。但是,当挑战以字节计分时,最好以字节计分APL,但在某处提及所使用的编码。
MtnViewMark'3

4

哈斯克尔- 217 185 182个字节

import Data.List
r g n m|m==n=max(head(g m)+1)((reverse.(0:).nub.sort$g(m-1)++g(m+1))!!1):g m|1<3=g m
j x=(-1)-minimum(0:(map(foldl r(\_->[0])x)[-1024..1024]>>=(tail>>=zipWith(-))))

用法:

j [1,2,1,2,1,2,1,2,2,2,2,1,0]

此函数建立了另一个函数,该函数返回给定x位置的磁体y位置列表。有了它,它计算所有x位置-1024 .. 1024的间隙并取最大值(编辑:现在我取最小值,因为间隙为负数:数字越小间隙越大)。


聪明的办法!希望你不要介意我打高尔夫球。
MtnViewMark 2014年

@MtnViewMark:完全没有。我发现3个其它字节保存:不要flip-,去负数,走minimum
nimi 2014年

在我的仓库中,您可以找到此代码42997-Magnetic.hs,其中还包括用于测试用例的测试工具以及用于显示雕塑的可视化工具。
MtnViewMark'1

3

Java语言,201 193

F=P=>{m=[];for(p of P){s=2;c=m[p]=m[p]||[];for(i=1e4;~i&&s;i--){if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;if(c[i-1]) s=0}c[++i]=1}g=-1;m.map(c=>{ d=0;for(i in c){g=i-d>g?i-d:g;d=++i} });return g}

F([1,1,2,2,2,2,2,2,1])=== 2

或可读版本

F=P=>{
  m=[];  // magnet positions
  for(p of P){ // every dropped magnet
    s=2; // initial speed
    c=m[p]=m[p]||[]; // column where magnet is dropping
    for(i=1e4;~i&&s;i--){ // continue until at floor or zero speed
      if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;  // magnet on either side, decrease speed
      if(c[i-1]) s=0; // magnet is directly below
    }
    c[++i]=1;
  }
  g=-1; // maximum gap
  m.map(c=>{ 
          d=0;for(i in c){g=i-d>g?i-d:g;d=++i;} 
       });
  return g;
};

2

Python 2.7、327

from itertools import * 
s=input()
if s:m=min(s);l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i];c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:];j=len(c)-c.index(1)-1-len(r) if any(c) else 0;l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

在进行空白高尔夫之前,它看起来像这样:

from itertools import * 
s=input()
if s:
    m=min(s)
    l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i]
    c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:]
    j=len(c)-c.index(1)-1-len(r) if any(c) else 0
    l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

这是对更复杂的行的解释,主要是出于我自己的利益。

l=[[] for _ in range(max(s)-m+3)] 

这将构造一个长度为max(drops)-min(drops)+1的空列表数组,并在任一侧添加一个占位符。我一直想写[[]] * K来构造一个空列表数组,但这会使K指针指向相同的空列表。

c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:] 

来自itertools的功能izip_longest与zip类似,但是将较短的列表填充为None以便将列表压缩在一起。切片[::-1]从“或”比较中反转0和1的列表。为了在下一行中使用index方法,该列表被反向,该方法查找元素的第一个实例。由于非空列的最后一个元素必须为1,因此这是反向列表中的第一个元素,并通过切片[1:]忽略。

j=len(c)-c.index(1)-1-len(r) if any(c) else 0 
l[i]=r+[0]*j+[1]

首先计算列i的长度与第二列1在相邻列中的位置之间的差。如果差异为正,则在添加1之前将许多零添加到第i列。任何非正数乘以[0]是空列表。

max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

来自itertools的groupby函数将列表拆分为连续元素的子序列。该行找到所有列中所有零子序列的长度的最大值。必须将每个子序列q强制转换为列表,因为groupby返回一个生成器(就像所有itertools函数一样),该生成器自然不支持len方法。


1

Java-281字节

非常简单。

首先,它以阵列形式构建雕塑

然后找到最大的差距。

int a(int[]b){
        int[][]d=new int[9999][9999];
        int g,r,t,y=-1;
        for(int c:b){
            c+=5000;
            g=0;
            for(r=9998;r>=0;r--){
                if(r==0||d[c][r-1]==1){d[c][r]=1;break;}
                if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}
            }
        }
        for(int[] k:d){
            t=0;
            for(int i:k){
                if(i==0)t++;
                else{if(t>y)y=t;t=0;}
            }
        }
        return y;
    }

小-

int a(int[]b){int[][]d=new int[9999][9999];int g,r,t,y=-1;for(int c:b){c+=5000;g=0;for(r=9998;r>=0;r--){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[] k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}

您可以通过更换先救一个字节|||。同样,返回y而不打印将节省9个字节。
Ypnypn 2014年

@Ypnypn,谢谢!顺便说一句,您的第一条语句似乎抛出ArrayIndexOutOfBounds异常(-1)。(我没有很多有关按位运算符的经验)
Stretch Maniac

它已经一年半,但你可以打高尔夫球更些:(272个字节int a(int[]b){int z=9999,d[][]=new int[z][z],g,r,t,y=-1;for(int c:b){c+=z/2;g=0;for(r=z;--r>-2;){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1|d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[]k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}。变更摘要:z=9999已添加并使用;intint[][]字段初始化已合并成一个; 第二个||被替换|; for(r=9998;r>=0;r--)已更改为for(r=z;--r>-2;)
凯文·克鲁伊森
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.