¿Es L-convexo?


14

Antecedentes

Un poliomino se llama L-convexo , si es posible viajar desde cualquier mosaico a cualquier otro mosaico por un camino en forma de L, es decir, un camino que va en las direcciones cardinales y cambia de dirección como máximo una vez. Por ejemplo, el poliomino de 1s en la figura

0 0 1 1 1 0

1 1 1 1 0 0

1 1 0 0 0 0

no es L-convexo, ya que ambas rutas en forma de L desde la parte inferior izquierda 1a la superior derecha 1contienen un 0:

0>0>1>1>1 0
^       ^
1 1 1 1 0 0
^       ^
1>1>0>0>0 0

Sin embargo, el poliomino de 1s en esta figura es L-convexo:

0 1 1 1 0 0

1 1 1 1 1 1

0 1 1 0 0 0

Entrada

Su entrada es una matriz 2D de bits en el formato nativo de su idioma, o como una cadena delimitada por una nueva línea si nuestro idioma carece de matrices. Se garantiza que contiene al menos uno 1.

Salida

Su salida será un valor verdadero si el conjunto de 1s es un poliomino L-convexo, y un valor falso si no. Estas salidas deben ser consistentes: debe generar el mismo valor verdadero para todas las entradas L-convexas, y el mismo valor falso para otras. Tenga en cuenta que un conjunto desconectado de 1s (que no es un poliomino) da como resultado una salida falsa.

Reglas y puntuación

Puede escribir un programa completo o una función. El conteo de bytes más bajo gana, y las lagunas estándar no se permiten.

Casos de prueba

Estos casos de prueba también deberían funcionar si gira o refleja las matrices, o agrega filas de 0s a cualquier borde.

False instances
01
10

111
101
111

1101
1111
1110

1100
1000
0011

01100
11110
01110
00110

011000
011110
001111

True instances
1

01
11

010
111
010

001
011
111

11100
11110
01100
01000

011000
011000
111100
111111
001000

Muy buen desafío, lo disfruté =)
flawr

Acerca de la entrada: ¿se permite una cadena delimitada por nueva línea , si nuestro idioma no carece de matrices ?
edc65

@ edc65 (Lo siento, estuve fuera de la red durante un par de días). Claro, eso también está permitido, está mal redactado por mi parte.
Zgarb

Respuestas:


6

Caracoles , 45 24

&
!{\1t\1!{o\1,nf\1,!.!~

Justo después de publicar mi solución inicial, me di cuenta de que había una manera mucho mejor. El programa original viajó alrededor del cuadrado formado por los caminos entre dos 1s, probando la presencia de un 0 en cada par de lados. También tenía que tener un caso especial para rutas de línea recta. La nueva versión comienza teletransportándose de uno 1a otro y probando la ausencia de una ruta recta o en forma de L de 1s de regreso al inicio.


¡¡DIOS MIO!! ¿Hay un intérprete en línea donde podamos jugar con esto?
flawr

1
@flawr Puede construirlo desde la fuente con el código fuente aquí .
Alex A.

6

Matlab, 182 bytes

Idea: Repita para cada 1en la matriz de poliomino:

  • Cree una nueva matriz con solo el dado 1pero el resto cero.
  • para cada 1en esta nueva matriz (repita hasta que ya nada cambie)
    • agregar 1como vecinos en la dirección x si hay 1como vecinos en el polinomio
  • para cada 1en esta nueva matriz (repita hasta que ya nada cambie)
    • agregar 1como vecinos en la dirección x si hay 1como vecinos en el polinomio

Ahora, 1en la nueva matriz debe cubrir todo 1en la matriz de polinomio a la que se puede llegar desde el punto de partida dado yendo primero en la dirección xy luego en la dirección y. Ahora podemos repetir el mismo proceso pero primero yendo en la dirección y y luego en la dirección x. Ahora se 1debe alcanzar cada una de las matrices de poliomino a la vez o ambas veces. Si no es así, entonces hemos encontrado una posición en la matriz de polinomio que no puede ser alcanzada desde cualquier otra posición mediante una Lruta.

Golfizado:

function r=f(a);[i,j,b]=find(a);N=nnz(i);r=1;for k=1:N;K=1:3;for l=1:2;c=b;b=a*0;b(i(k),j(k))=1;for z=1:2*N; b=conv2(b+0,K,'s')&a;if z==N;K=K';end;end;end;r=r*all(b(:)|c(:)>=a(:));end

Con comentarios:

function r=codegolf_L_convex(a);
%a=[0,1;1,1];
[i,j,b]=find(a);%b just needs to be initialized, does not really mattter
N=nnz(i);%number of ones in the matrix
r=1;%return value
for k=1:N;%go throu all '1' in the matrix
    %expand that pixel in x dir:
    K=1:3;%convolution kernel (just three positive values needed)
    for l=1:2;%first horizontal->vertical then vertical->horizontal
        c=b;%backup for considering both runs
        b=a*0;
        b(i(k),j(k))=1; %set the seed
        for z=1:2*N;     
            b=conv2(b+0,K,'s')&a; %expand the seed horizontally (or vertically for the second half) but only within the polyomino
            if z==N;
                K=K'; %change horizontal/vertical 
            end;
        end;
    end;
    r=r*all(b(:)|c(:)>=a(:));%check whether we can really reach every point
end

Script de casos de prueba:

disp('all false -------------');
a=[0,1;1,0];
f(a)
a=[1,1,1;1,0,1;1,1,1];
f(a)
a=[1,1,0,1;1,1,1,1;1,1,1,0];
f(a)
a=[1,1,0,0;1,0,0,0;0,0,1,1];
f(a)
a=[0,1,1,0,0;1,1,1,1,0;0,1,1,1,0;0,0,1,1,0];
f(a)
a=[0,1,1,0,0,0;0,1,1,1,1,0;0,0,1,1,1,1];
f(a)
 disp('all true +++++++++++++');
a=[1];
f(a)
a=[0,1;1,1];
f(a)
a=[0,1,0;1,1,1;0,1,0];
f(a)
a=[0,0,1;0,1,1;1,1,1];
f(a)
a=[1,1,1,0,0;1,1,1,1,0;0,1,1,0,0;0,1,0,0,0];
f(a)
a=[0,1,1,0,0,0;0,1,1,0,0,0;1,1,1,1,0,0;1,1,1,1,1,1;0,0,1,0,0,0];
f(a)

2

Javascript ES6, 290 bytes

Ok, tal vez no gane ningún premio por brevedad, pero sí utiliza un enfoque novedoso. Vea la versión sin golf de cómo funciona.

La prueba de este método se puede encontrar en: Autómatas celulares y sistemas complejos discretos .

L=a=>[1,0,1].every($=>(a=a[0].map((_,col)=>a.map(row=>row[col]))).map(r=>($?r.reverse():r).join``).every((r,i,b)=>r.replace(/^(0*)(1*)(0*)$|(.+)/,(_,s,m,o,e)=>(c=e)?'':!m||b[i-1]&&+b[i-1][s.length]?1:b.every((r,j)=>j<i||(c=c||!+r[l=s.length])?r.search(`0{${l}}.*0{${o.length}}`)+1:1)||'')))

Sin golf:

function L(a) {
  /* Runs three times and ensure all pass validation
   * 1: horizontally reversed
   * 2: 90 degrees rotated
   * 3: original
   *
   *     | 1:  | 2:  | 3:
   * =====================
   * 001 | 100 | 111 | 001
   * 011 | 110 | 011 | 011
   * 111 | 111 | 001 | 111
   *
   * By finding maximal rectangles with corners on all NW and NE corners
   * (separately) of a HV-convex polyomino and ensuring it doesn't enter the
   * boundaries labelled ABCD for the rectangle X below:
   *
   *   A  |         |  B
   * -----===========-----
   *      |    X    |
   * -----===========-----
   *   C  |         |  D
   *
   * The first iteration tests the NE corners and horizontal convexity.
   * The second iteration test vertical convexity.
   * The third iteration tests the NW corners.
   *
   * If all pass then the polyomino is L-convex.
   */
  return [1,0,1].every(function($){
    return (a=a[0].map((_,col)=>{
      // Transpose rows with columns
      return a.map(row=>row[col])
    })).map(row=>{
      // Join rows as strings and on odd iterations reverse them
      return ($ ? row.reverse() : row).join``
    }).every(function(row, i, b) {
      if (i == 0) console.log(b.join('\n'));
      return row.replace(/^(0*)(1*)(0*)$|(.+)/, function(_, start, middle, end, invalid) {
        // Non H-convex polyomino (0 between 1s)
        if (invalid) return '';
        // Is not a NW corner (character above is 1)
        if (!middle || b[i-1] && +b[i-1][start.length]) return 1;
        c=1;
        return b.every(function(row, j) {
          // Above or below maximal rectangle from corner
          if (j < i || !(c=c&&+row[l=start.length])) {
            // Area before and after maximal rectangle doesn't contain 1
            return row.search(`0{${l}}.*0{${end.length}}`)+1
          }
          return 1;
        }) || '';
      });
    });
  });
}

1
¡Ja, ese artículo es donde obtuve la inspiración para este desafío!
Zgarb

@Zgarb El artículo fue excelente y uno de los pocos que pude encontrar que tenía sentido para alguien que no tiene una orientación matemática.
George Reith

2

Mathematica, 129 127 bytes

3>GraphDiameter@Graph[#,#<->#2&@@@Select[#~Tuples~2,!FreeQ[#-#2&@@#,0]&]]&@Position[#,1]&&{#,Thread@#}~FreeQ~{___,1,0..,1,___}&

Explicación:

Primero, si hay 0entre dos 1s en la misma fila o columna, la matriz no es L-convexa, porque no podemos conectar los dos 1s.

Después de excluir este caso, cada dos 1s en la misma fila o columna se pueden conectar por una ruta recta. Podemos generar un gráfico, cuyos vértices son las posiciones de 1s en la matriz, y los bordes son pares de 1s en la misma fila o columna. Entonces la matriz es L-convexa si y solo si el diámetro del gráfico es menor que 3.


1
¿Puedes dar una explicación de cómo funciona esto? No voy a votar galimatías que nadie podría entender =)
flawr

¿Cómo reconoce esto la primera y cuarta instancias falsas (las desconectadas)?
Zgarb

1
@ Zgarb Si el gráfico está desconectado, su diámetro es infinito.
alephalpha

2

JavaScript (ES6) 174

Mirando la cuadrícula de celdas vacías o llenas, para cualquier par de celdas llenas verifico las rutas horizontales a la otra columna de celdas (puede haber 1 si las celdas están en la misma fila, de lo contrario o 2) y las rutas verticales a la otra fila de celdas (puede haber 1 o 2 también). Si encuentro una celda vacía en ambas rutas verticales o en ambas rutas horizontales, entonces no puede haber una ruta en forma de L entre las celdas.

(Me costó mucho tratar de poner esta explicación, espero haber sido claro)

Pruebe a ejecutar el fragmento a continuación en cualquier navegador compatible con EcmaScript 6

F=p=>!p.some((n,y)=>n.some((q,x)=>q&&p.some((o,u)=>o.some((q,t)=>{for(f=0,i=y;q&i<=u;i++)f|=!p[i][x]|2*!p[i][t];if(f<3)for(f=0,j=x;q&j<=t;j++)f|=!n[j]|2*!o[j];return f>2}))))

// TEST
console.log=(...x)=>O.innerHTML+=x+'\n'

tko = [
 [[0,1],[1,0]]
,[[1,1,1],[1,0,1],[1,1,1]]
,[[1,1,0,1],[1,1,1,1],[1,1,1,0]]
,[[1,1,0,0],[1,0,0,0],[0,0,1,1]]
,[[0,1,1,0,0],[1,1,1,1,0],[0,1,1,1,0],[0,0,1,1,0]]
,[[0,1,1,0,0,0],[0,1,1,1,1,0],[0,0,1,1,1,1]]
]
tko.forEach(t=>(console.log(t.join`\n`+`\nFalse? ${F(t)}\n`)));
tok = [
 [[1]]
,[[0,1],[1,1]]
,[[0,1,0],[1,1,1],[0,1,0]]
,[[0,0,1],[0,1,1],[1,1,1]]
,[[1,1,1,0,0],[1,1,1,1,0],[0,1,1,0,0],[0,1,0,0,0]]
,[[0,1,1,0,0,0],[0,1,1,0,0,0],[1,1,1,1,0,0],[1,1,1,1,1,1],[0,0,1,0,0,0]]
]  
tok.forEach(t=>(console.log(t.join`\n`+`\nTrue? ${F(t)}\n`)));

// LESS GOLFED

U=p=>
  !p.some((n,y)=>  
    n.some((q,x)=> 
      q && p.some((o,u)=>  
        o.some((q,t)=>{
          for(f=0,i=y; q&i<=u; i++)f|=!p[i][x]|2*!p[i][t]
          if (f<3)
            for(f=0,j=x; q&j<=t; j++)f|=!n[j]|2*!o[j]
          return f>2
        })
      )
    )
  )
<pre id=O></pre>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.