Esculturas Magnéticas

14

Esta é uma continuação frouxa do meu desafio anterior na construção de gráficos .

fundo

Um artista excêntrico contratou você para estimar a integridade estrutural de suas esculturas. Ele cria suas obras de arte pegando um monte de ímãs em forma de cubo e largando-os um a um em uma pilha enorme. Para analisar melhor seu método, usamos o seguinte modelo bidimensional. Começamos com um piso vazio e soltamos um ímã #em qualquer coordenada inteira, digamos 0:

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

Se outro ímã cair 0, ele termina em cima do anterior:

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

Agora, vamos soltar mais um ímã em 0e depois um em 1:

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

Como visto acima, um ímã em queda adere ao segundo ímã por onde passa (o primeiro apenas o retarda). O segundo ímã não precisa estar diretamente abaixo do primeiro, e um ímã de ambos os lados ainda conta como um ímã:

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

Os artistas querem que você calcule o intervalo vertical máximo na escultura final, ou seja, o número máximo de espaços vazios entre dois ímãs na mesma coluna ou um ímã e o solo abaixo dela. Na figura acima, esse número seria 3 (na coluna 2).

Entrada

Uma lista de números inteiros, representando as coordenadas em que o artista coloca seus ímãs, lida da esquerda para a direita. Você pode assumir que as coordenadas são satisfatórias -1024 <= i < 1024e que o comprimento da lista é no máximo 1024, se isso ajudar.

Resultado

A lacuna vertical máxima na escultura final. A escultura vazia tem lacunas -1, e este caso deve ser incluído, pois nosso escultor é um dadaísta.

Regras adicionais

Você pode atribuir uma função ou um programa completo. A menor contagem de bytes vence e as brechas padrão não são permitidas. Código com explicações é o preferido.

Casos de teste

[] -> -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
Zgarb
fonte

Respostas:

1

Dyalog APL, 73 70 caracteres

{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
ngn
fonte
Nota: Isso tem 122 bytes (o desafio está em bytes), assumindo UTF-8.
precisa saber é o seguinte
Sou bastante compreensivo: muitas vezes fui enganado por usar caracteres não ASCII no meu Haskell. Desde então, fico atenta se o Q especifica contagem por caracteres ou bytes.
precisa saber é o seguinte
@MtnViewMark Pontuação por bytes não significa pontuação por bytes UTF-8. Fazer isso para a APL é punir por ser muito velho para reconhecer o ASCII como um padrão importante. O conjunto de caracteres da APL se encaixa facilmente em uma página de código de byte único e essa página de código existe . Então, usando essa página de código como codificando cada caractere é um byte. Por outro lado, se você usar caracteres não ASCII no Haskell, precisará usar uma codificação que contenha os caracteres ASCII e não ASCII - e isso geralmente é UTF-8.
Martin Ender
@ngn - depois de ler a maioria dos meta posts sobre isso, parece que as coisas ainda estão lamacentas. No entanto, talvez seja melhor, quando o desafio é pontuado em bytes, pontuar APL em bytes, mas mencionar em algum lugar a codificação usada.
precisa saber é o seguinte
4

Haskell - 217 185 182 Bytes

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(-))))

Uso:

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

Essa função cria outra função que retorna uma lista de posições y do ímã para uma determinada posição x. Com ele, calcula os intervalos para todas as posições x -1024 .. 1024 e leva o máximo (Edit: agora estou levando o mínimo, porque os intervalos são negativos: quanto menor o número, maior o intervalo).

nimi
fonte
Abordagem inteligente! Espero que você não se importe que eu diminua um pouco.
MtnViewMark
@MtnViewMark: De maneira alguma. Eu encontrei mais 3 bytes para salvar: não flipo -, ir com os números negativos e tomar o minimum.
N /
No meu repositório, você pode encontrar esse código, 42997-Magnetic.hs, que também inclui um equipamento de teste para os casos de teste e um visualizador que exibe as esculturas.
precisa saber é o seguinte
3

Javascript, 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

Ou versão legível

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;
};
zabalajka
fonte
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)])

Antes do espaço em branco, fica assim:

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)])

Aqui está uma explicação das linhas mais complexas, principalmente para meu próprio benefício.

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

Isso constrói uma matriz de listas vazias de comprimento max (drops) -min (drops) +1 mais um espaço reservado em ambos os lados. Eu sempre quero escrever [[]] * K para construir uma matriz de listas vazias, mas isso faz com que K aponte para a mesma lista vazia.

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

A função izip_longest do itertools é como zip, mas preenche a lista mais curta com None para compactar as listas. A divisão [:: - 1] inverte a lista de 0 e 1 da comparação "ou". A lista é revertida para usar o método index na próxima linha, que localiza a primeira instância de um elemento. Como o último elemento de uma coluna não vazia deve ser 1, este é o primeiro elemento da lista invertida e é ignorado pela fatia [1:].

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

Primeiro, calcule a diferença entre o comprimento da coluna ie a posição do segundo 1 nas colunas adjacentes. Se a diferença for positiva, adicione muitos zeros à coluna i antes de adicionar um 1. Qualquer número não positivo vezes [0] é a lista vazia.

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

O grupo de funções de itertools divide uma lista em subsequências de elementos consecutivos. Esta linha encontra o máximo dos comprimentos de todas as subsequências de zeros em todas as colunas. É necessário converter cada subsequência q em uma lista, porque groupby retorna um gerador (como todas as funções de ferramentas) que naturalmente não suporta um método len.

user2487951
fonte
1

Java - 281 bytes

Bem direto.

Primeiro ele constrói a escultura em uma matriz

Então encontra a maior lacuna.

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;
    }

pequeno -

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;}
Stretch Maniac
fonte
Você pode salvar um byte, substituindo o primeiro ||por |. Além disso, ao retornar em yvez de imprimir, ele salva 9 bytes.
Ypnypn
@Ypnypn, Thanks! BTW, sua primeira instrução parece lançar uma exceção ArrayIndexOutOfBounds (-1). (Eu não tenho muita experiência com operadores bit a bit) #
Stretch Maniac
Foi cerca de 1,5 anos, mas você pode golfe um pouco mais: ( 272 bytes ): 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;}. Resumo das alterações: z=9999foi adicionado e usado; inte a int[][]inicialização do campo foi mesclada em um; o segundo ||é substituído por |; for(r=9998;r>=0;r--)foi alterado parafor(r=z;--r>-2;)
Kevin Cruijssen