Reconhecer uma videira

31

fundo

Eu tenho um monte de imagens em preto e branco antigas e granuladas. Alguns deles mostram videiras subindo em uma parede, outros não - sua tarefa é classificá-los para mim.

Entrada e saída

Sua entrada é uma matriz 2D retangular de bits A , fornecida em qualquer formato conveniente. Não ficará vazio, mas não é garantido que ele contenha 0 e 1. A matriz representa uma videira se as seguintes condições forem válidas:

  • A linha inferior de A contém pelo menos um 1. Essas são as raízes da videira.
  • Cada 1 em A é conectado à linha inferior por um caminho de 1s que só vai para a esquerda, direita e para baixo (não para cima nem para a diagonal). Esses caminhos são os ramos da videira.

Sua saída é um valor de verdade consistente se a entrada representar uma videira e um valor de falsy consistente caso contrário.

Exemplos

Essa matriz representa uma videira:

0 0 1 0 0 1
0 1 1 0 0 1
0 1 0 1 1 1
1 1 0 1 0 1
0 1 1 1 0 1
0 0 1 0 1 1

Essa entrada não representa uma videira, pois há um 1 no meio da borda direita que não está conectado às raízes por um ramo:

0 0 0 1 1 0
0 1 0 1 1 1
0 1 0 1 0 1
0 1 1 1 1 0
0 0 1 1 0 1

A matriz all-0 nunca representa uma videira, mas a matriz all-1 sempre representa.

Regras e pontuação

Você pode escrever um programa completo ou uma função. A menor contagem de bytes vence e as brechas padrão não são permitidas.

Casos de teste

Entradas verdadeiras:

1

0
1
1

01
11

0000
0111
1100
1001

1111
1111
1111
1111

001001
011001
010111
110101
011101
001011

1011011
1001001
1111111
0100000
0111111
1111001
1001111
1111101

0000000
0011100
0010100
0011100
0001000
1111111
0001000
0011100
0010100
0010100

Entradas falsas:

0

1
0

10
01

000
000
000

011
110
000

111111
000000
101011
111001

010010
001000
000010
110001

001100
111111
110101
010011
111011

000110
010111
010101
011110
001101

11000000
10110001
10011111
11110001
01100011
00110110
01101100
01100001
01111111
Zgarb
fonte
1
Não percebeu que vinha não pode crescer para baixo, teve uma boa idéia usar componentes ligados de um gráfico, suspiro ...
swish
@swish Tudo o que isso significa é que a remoção de cada linha por sua vez deve continuar resultando em um gráfico conectado a uma linha de 1s na parte inferior.
314 Neil

Respostas:

26

Caracóis , 25 19 17 bytes

&
\0z),(\1dlr)+d~

Experimente online!

Explicação

O Snails é uma linguagem de correspondência de padrões 2D inspirada no regex, que foi originalmente desenvolvida para o nosso desafio de design de linguagem de correspondência de padrões 2D .

O &Snails faz o teste do padrão a partir de todas as posições iniciais possíveis e imprime 0ou 1depende se o padrão falha em algum deles ou combina com todos eles.

Agora o Snails pode trabalhar com parênteses implícitos, portanto, o padrão é uma abreviação para o seguinte:

(\0z),(\1dlr)+d~

O ,age como um *em regex (ie corresponder zero ou mais vezes), enquanto o +é o mesmo que em regex (coincidir com uma ou mais vezes). Então começamos combinando \0zquantas vezes for necessário, o que corresponde a um único 0e, em seguida, permite que o caracol redefina sua direção arbitrariamente z. Isso permite zeros na entrada, desde que uma célula de videira válida possa ser encontrada em qualquer outro lugar.

Em seguida, combinamos pelo menos um \1dlr, que corresponde a um único 1e, em seguida, permite que o caracol redefina sua direção para baixo, esquerda ou direita. Observe que, se a célula em que começamos contiver um 1, apenas corresponderemos a esta parte. Basicamente, permite que o caracol atravesse uma videira de um galho até as raízes.

Finalmente, precisamos garantir que alcançamos o solo procurando uma célula fora dos limites ( ~) abaixo ( d).

Martin Ender
fonte
1
Estou agradavelmente surpreso que ninguém foi capaz de seguir a documentação :)
feersum
3

JavaScript (ES6), 135 bytes

s=>s.replace(/^[^1]*\n/,``).split`
`.map(s=>+`0b${s}`).reverse(g=(n,m,o=(m<<1|m|m>>1)&n)=>n-m?o-m&&g(n,o):n).reduce((m,n,i)=>g(n,n&m))

Nota: Devido a limitações do tipo inteiro, funciona apenas para videiras com até 31 caracteres de largura. Explicação: Cada linha é AND AND bit a bit com a linha adjacente para determinar os pontos de conexão e, em seguida, a gfunção é usada para expandir recursivamente a linha horizontalmente até que não possa mais expandir. Por exemplo, se duas linhas adjacentes estiverem 1110111e, em 1011100seguida, os pontos de conexão estiverem, 1010100isso será expandido para 1110110e 1110111então descobrirá que a linha está conectada. Se a gfunção falhar, retornará zero, o que gfará com que todas as funções subsequentes falhem também, e o resultado será falso. Se a gfunção for bem-sucedida, ela retornará a nova linha que será propagada através do reduceteste da próxima linha.

s=>s.replace(/^[^1]*\n/,``)         Remove irrelevant leading "blank" rows
    .split`\n`                      Split into lines
    .map(s=>+`0b${s}`)              Convert into binary
    .reverse(                       Process from bottom to top
     g=(n,m,o=(m<<1|m|m>>1)&n)=>     Expand row horizontally
      n-m?o-m&&g(n,o):n)             Check whether rows are connected
    .reduce((m,n,i)=>g(n,n&m))      Check all rows
Neil
fonte
Vou declarar que 31 caracteres são largos o suficiente e essa abordagem é válida.
Zgarb
2

Python 2, 254 bytes

Nenhuma biblioteca

def f(A,r=0,c=-1):
 B=A[r];R=len(A)-1;C=len(B);i=1 in A[R]
 if c<0:
    for j in range(R*C+C):
        if A[j/C][j%C]:i&=f(A,j/C,j%C)
    return i&1
 _=B[c];B[c]=0;i=_&(r==R)
 if _:
    if c>0:i|=f(A,r,c-1)
    if r<R:i|=f(A,r+1,c)
    if c<C-1:i|=f(A,r,c+1)
 B[c]=_;return i

Observe que os recuos do segundo e terceiro nível são formados com guias na contagem de bytes.

Experimente online

Chuck Morris
fonte
1

Wolfram - 254

Passe algum tempo fazendo esse trabalho, então vou deixar aqui:

f[s_]:=(
v=Characters@StringSplit@s;
{h,w}=Dimensions@v;
g=GridGraph@{w,h};
r=First/@Position[Flatten@v,"0"];
g=VertexDelete[Graph[VertexList@g,
EdgeList@g/.x_y_/;Abs[x-y]>1yx],r];
v=VertexList@g;
v≠{}∧v~Complement~VertexOutComponent[g,Select[v,#>w h-w&]]{}
)

Basicamente, construo um gráfico de grade com as bordas direcionadas apontando para cima, remova os vértices que correspondem a 0s, verifico se os componentes inferiores do vértice contêm todos os vértices. Ridículo, eu sei ...

swish
fonte
2
Por que isso não é competitivo?
Downgoat 31/05
1
No momento, consideraríamos isso "não uma resposta", pois não é um jogo de golfe. Se você simplesmente remover espaços em branco desnecessários e adicionar uma contagem de bytes, não vejo razão para que isso não seja competitivo.
Alex A.
0

Python + NumPy 204 202 195 Bytes

from numpy import*
def f(A):
 r,c=A.shape
 z,s=zeros((r,1)),array([0,2,c+3])
 B=hstack((z,A,z)).flat
 for i in range(1,(r-1)*(c+2)):
    if B[i]and not any(B[s]):return 1<0
    s+=1
 return any(B[i:])

Espera Aser uma matriz numpy 2D.

Pega a matriz, apóia zero colunas à esquerda e à direita e nivela a matriz. sé um estêncil que aponta para o elemento esquerdo, direito e inferior. O loop verifica cada elemento, exceto a última linha, se for, 1e pelo menos um de seu estêncil é 1, retorna Falsecaso contrário. Depois, verifique se a última linha contém alguma 1.

Dois casos de teste para você:

I1 = '001001\n011001\n010111\n110101\n011101\n001011'
A1 = array([int(c) for c in I1.replace('\n','')]).reshape(6,6)
print f(A1) #True

I2 = '001100\n111111\n110101\n010011\n111011'
A2 = array([int(c) for c in I2.replace('\n','')]).reshape(5,6)
print f(A2) #False

Edit1: 1<0 é menor queFalse

Edit2: flaté uma boa alternativa para flatten()e usando tabuladores para a segunda intenção no loop

Karl Napf
fonte