Determinar si la tierra está completamente cercada por cercas

19

Imagine una matriz bidimensional de valores booleanos, donde los 0 representan cuadrados de hierba en un terreno rectangular y los 1 representan cercas.

Escriba una función que acepte la matriz 2D como entrada y determine si puede viajar desde cualquier área de hierba a cualquier otra área de hierba, utilizando solo movimientos norte / este / oeste / sur, sin toparse con una cerca.

Si cualquier área de hierba en la matriz está completamente encerrada por cercas (lo que significa que no puede viajar N / E / W / S para llegar a cualquier otra área de hierba en la matriz), la función debería devolver falso; de lo contrario, debería volver verdadero.

A continuación hay dos matrices de muestra que puede usar como entradas, aunque su función debería poder manejar no solo estas, sino también cualquier matriz 2D de valores booleanos:

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

(should return true)

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

(should return false, since the middle 0 in the top row is fully enclosed)

El código de trabajo más corto gana. Elegiré al ganador después de que haya pasado una semana o no haya habido nuevos envíos en 24 horas.

jawns317
fuente
¿Puedes también prohibir operadores binarios? Me encantaría ver qué pensaría la gente.
Pierre Arlaud
Creo que esto es muy similar a un problema de USACO del año pasado (temporada 2012/2013). Hay algunos casos de prueba enormes a los que se puede acceder allí ...
apnorton
¿El tamaño de la matriz siempre será 5 * 5?
ProgramFOX
1
@ProgramFOX Suponga que la matriz podría tener cualquier altura, cualquier ancho. Y claro, saca algo booleano.
jawns317
1
¿Qué pasa con la matriz 3X3 1 1 1? 1 0 1; 1 1 1? Hay una celda de hierba en el centro. Visualmente, la celda de hierba en el centro está completamente encerrada por cercas, pero, según su definición, no lo está.
emory

Respuestas:

1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2
Max Jaderberg
fuente
1
@ jawns317 No veo por qué esta es la respuesta aceptada. Esto no es una función. La única otra respuesta que no es una función acepta de stdin. Este ni siquiera hace eso.
Tim Seguine
1
La aceptación de la entrada estándar se podría hacer como tal input('');c=bwconncomp(~ans,4);c.NumObjects<2Esto lo convertiría en 45 caracteres.
Dennis Jaheruddin
7

APL (39)

{∧/,⊃{⍺∨⊖⍵}/{⍵∨(∧\~⍵)∨⌽∧\⌽~⍵}¨s,⊖¨s←⊂⍵}

Uso:

      board1 board2
 0 0 0 0 0  0 1 0 1 0 
 0 1 0 0 0  0 1 1 0 0 
 0 1 1 1 1  0 0 0 0 0 
 0 0 0 0 0  0 0 0 1 0 
 0 0 0 1 1  1 1 1 1 0 
      {∧/,⊃{⍺∨⊖⍵}/{⍵∨(∧\~⍵)∨⌽∧\⌽~⍵}¨s,⊖¨s←⊂⍵} ¨ board1 board2
1 0
marinus
fuente
99
El beneficio de APL es que se parece tanto al ruido de la línea que nadie quiere verificar que sea correcto.
Tim Seguine
@Tim Cualquiera puede descargar un intérprete para ejecutarlo y verificar.
Gareth
3
@Gareth Sí, se suponía que el comentario era irónico.
Tim Seguine
@Tim Oh lo siento. Me perdí eso. :-(
Gareth
4

Mathematica, 60 58 caracteres

f=Max@MorphologicalComponents[1-#,CornerNeighbors->1>2]<2&

Uso:

f[{{0, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 1, 1}}]

Cierto

f[{{0, 1, 0, 1, 0}, {0, 1, 1, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 1, 0}, {1, 1, 1, 1, 0}}]

Falso

alephalpha
fuente
2
Misma duraciónf=Max@WatershedComponents[Image@#,CornerNeighbors->1>2]<2&
Dr. belisarius
3

Rubí, 202 198 193

a=$<.read.split('
').map(&:split)
f=->x,y{a[x][y]=1
[[-1,0],[1,0],[0,-1],[0,1]].map{|o|d,e=x+o[0],y+o[1]
f[d,e]if a[d]&&a[d][e]==?0}}
f[i=a.index{|x|x.index ?0},a[i].index(?0)]
p !(a.join=~/0/)

Hace un relleno de inundación, luego verifica si quedan 0 ceros.

Pomo de la puerta
fuente
¡Maldición! Si no hubiera probado mi código primero, habría sido más rápido. ;)
Tim Seguine
@Tim ¡Pero entonces habría estado mal! : P
Pomo de la puerta
3

PHP 147 202 177 165 149 bytes

EDITAR He superado mi truco gzip con una solución php real.

Un poco largo ... ingresado como una cadena de texto, sin espacios, filas delimitadas por nuevas líneas. Se inunda con cs y luego se comprueba para ver si quedan ceros. En el bucle que usoexp como límite superior bruto en el número de iteraciones requeridas. Aprovecho la simetría para manejar los casos duplicados en menos código

function f($s){$r=strpos;$n=$r($s,'
');$s[$r($s,'0')]=c;for(;$i++<1<<$n;)$s=strrev(ereg_replace('0(.{'.$n.'})?c','c\1c',$s));return!1==$r($s,'0');}

Aquí hay un caso de prueba sin golf:

<?php
$s1="00000
01000
01111
00000
00011";

$s2="01010
01100
00000
00010
11110";

function f($s){
    $n=strpos($s,"\n");
    $s[strpos($s,'0')]=c;
    for(;$i<strlen($s);++$i)
        $s=strrev(ereg_replace(
            '0(.{'.$n.'})?c',
            'c\1c'
            ,$s));
    return!1===strpos($s,'0');
}

var_dump(f($s1));
var_dump(f($s2));
Tim Seguine
fuente
3

Excel VBA, 305 215 Bytes

Sí, jaja VBA , pero la naturaleza matricial del problema sugiere que una solución práctica en Excel podría ser interesante (¡Además, alguien ya ha enviado una respuesta en mis otros idiomas!). Obviamente, VBA no va a ser el más breve, pero creo que es razonable.

Esta inundación se llena desde un punto de partida arbitrario y luego verifica si queda alguna "hierba"

R es un rango de hoja de trabajo con 1 y 0 que representan las cercas y el césped como se define en el problema. Bono, el campo de juego no tiene que ser rectangular o incluso contiguo.

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

Por ejemplo, devolvería False. No se puede llegar a los ceros a la derecha desde los ceros a la izquierda. El campo irregular no lo rompe.

Function F(R)
L R, R.Find(0)
F = Not IsNumeric(R.Find(0))
End Function

Sub L(R, S As Range)
If S Or IsEmpty(S) Then Exit Sub
S = 1
L R, S.Offset(1, 0)
L R, S.Offset(-1, 0)
L R, S.Offset(0, 1)
L R, S.Offset(0, -1)
End Sub

Algunas notas sobre el golf.

Creo que algunos caracteres podrían recortarse si el requisito se invirtió con respecto a 1 y 0, pero no lo suficiente como para que valga la pena invertirlo.

VBA insiste en un grupo de espacios en blanco (a = b vs a = b), lo que no ayuda al recuento de caracteres.

S debe declararse explícitamente como un rango. Si se deja una variante, se convierte en un valor de rango en lugar de un rango.

Tal vez una mejor manera de ramificar la inundación? No pude encontrar un bucle que guardó caracteres para enviarlo N / E / S / W

Editar: reconsideró el caso base en el relleno de inundación, logró recortar bastante comprobando si está en un caso base después de la recursión en lugar de prevenir la recursividad.

Tre
fuente
2

Python (219 bytes)

Definitivamente no es el más corto, pero es mi primer intento aquí, así que estoy orgulloso de ello:

def f(n):
 m=[int(c) for c in n if c!='\n']
 for i in range(len(m)):
  if m[i]<1:m[i]=2;break
 g(m,n.find('\n'),i);return not 0in m
def g(n,w,i):
 for x in i-w,i-1,i+1,i+w:
  if 0<=x<len(n):
   if n[x]<1:n[x]=2;g(n,w,x)

Su entrada debe ser una Cadena de 0s y 1s donde las filas están delimitadas por un carácter de nueva línea (\ n).

Ejemplo de uso:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False
PsHegger
fuente
puedes combinar las dos últimas declaraciones if en una sola and, creo que ahorra algunos caracteres
Tim Seguine
Puede usar el tabulador como 8 espacios.
Konrad Borowski
2

Pitón (196)

Llenado de inundación estándar.

g=raw_input()
m=g.find(' ')
g=g.replace(' ','')
V={}
def D(V,x):
 if V.get(x,0)or g[x]=='1':return
 V[x]=1;[D(V,x+i)for i in 1,-1,m,-m if 0<=x+i<len(g)]
D(V,g.find('0'))
print len(V)==g.count('0')

Toma la matriz a través de STDIN con cada fila separada por un solo espacio. Por ejemplo "01010 01100 00000 00010 11110".

Sudharsan Mohan
fuente
2

Mathematica 53

f=Max@(Symbol@@Names@"I*`i*B*l")[Image[1-#],0,1>2]<2&

Llama a la función interna Image`MorphologicalOperationsDump`imageBinaryLabel, que es similar a MorphologicalComponents.

f[{{0, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 1, 1}}]
f[{{0, 1, 0, 1, 0}, {0, 1, 1, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 1, 0}, {1, 1, 1, 1, 0}}]

Cierto

Falso

ybeltukov
fuente
1

PHP (286 caracteres)

Demasiado tiempo, probablemente he recorrido un largo camino.

function D($a){$x=count($a);$y=count($a[0]);for($i=0;$i<$x;$i++)$a[$i][-1]=$a[$i][$y]=1;for($j=0;$j<$y;$j++)$a[-1][$j]=$a[$x][$j]=1;for($i=0;$i<$x;$i++){for($j=0;$j<$y;$j++){if($a[$i][$j]!=1){if($a[$i][$j-1]==1&&$a[$i][$j+1]==1&&$a[$i-1][$j]==1&&$a[$i+1][$j]==1)return 0;}}}return 1;}

No golfizado:

function D($a)
{
$x=count($a);
$y=count($a[0]);
for ($i=0;$i<$x;$i++)
    $a[$i][-1]=$a[$i][$y]=1;
for ($j=0;$j<$y;$j++)
    $a[-1][$j]=$a[$x][$j]=1;
for ($i=0;$i<$x;$i++)
{
    for ($j=0;$j<$y;$j++)
    {
        if ($a[$i][$j] != 1)
        {
            if ($a[$i][$j-1] == 1 && $a[$i][$j+1] == 1 && $a[$i-1][$j] == 1 && $a[$i+1][$j] == 1)
                return 0;
        }
    }
}
return 1;
}
Vereos
fuente
Esto no es correcto Solo verifica si no hay ceros individuales que estén rodeados por unos. Hay formas más complicadas de eliminar los ceros.
Tim Seguine
Por supuesto que tienes razón. Estaba buscando otra forma de resolver esto sin inundaciones, ¡creo que mi búsqueda continúa!
Vereos
Es solo un problema de accesibilidad gráfica, y el relleno en este caso es básicamente floyd-warshall sin crear o representar explícitamente el gráfico de accesibilidad. Podría intentar extraer el gráfico y hacer el cierre transitivo usted mismo, pero supongo que será más largo.
Tim Seguine
1

C #, 235 bytes

int[][]D;int w,h,n;bool Q(int x,int y){var r=x>=0&&x<w&&y>=0&&y<h&&(D[x][y]++==0);if(r){Q(x-1,y);Q(x+1,y);Q(x,y+1);Q(x,y-1);}return r;}
bool P(int[][]B){D=B;w=D[0].Length;h=D.Length; for(int i=0;i<w*h;i++)if(Q(i%w,i/w))n++;return n==1;}

Intenta rellenar cada celda del tablero, hace que solo un relleno de inundación sea verdadero.

bool R( int x, int y)
{
    var r = (x >= 0 && x < w && y >= 0 && y < h && D[x, y]++ == 0);
    if (r)
    {
        R(x-1, y);
        R(x+1, y);
        R(x, y+1);
        R(x, y-1);
    }
    return r;
}

public bool Do()
{
    D = Board1;
    w = D.GetLength(0);
    h = D.GetLength(1);
    for (int x = 0; x < w; x++) for (int y = 0; y< h; y++) if (R(x, y)) n++;
    return n == 1;
}
Blau
fuente
0

Python 2.X + 3.X: 335 caracteres

Golfizado:

def f(n):
 x,y=0,0
 z=lambda x,y:y<len(n)and x<len(n[0])and n[x][y]!=1
 while not z(x,y):
  y+=1
  if y==len(n):
   y=0
   x+=1
  if x==len(n[0]):
   return False
 t=set([(x,y)])
 v=set()
 while t:
  (x,y)=t.pop()
  v|=set([(x,y)])
  if z(x+1,y):
   t|=set([(x+1, y)])
  if z(x,y+1):
   t|=set([(x, y+1)])
 return len(v)+sum(map(sum,n))==len(n)*len(n[0])

Sin golf:

def f(n):
    """In the following filed, starting from a 0: is it possible to
       get to every other 0?

        >>> f([[0,0,0,0,0],\
               [0,1,0,0,0],\
               [0,1,1,1,1],\
               [0,0,0,0,0],\
               [0,0,0,1,1]])
        True
        >>> f([[0,1,0,1,0],\
               [0,1,1,0,0],\
               [0,0,0,0,0],\
               [0,0,0,1,0],\
               [1,1,1,1,0]])
        False
        >>> f([[1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1]])
        False
        >>> f([[1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,0,1,1,1],\
               [1,1,1,1,1]])
        True
        >>> f([[1,1,1,1,1],\
               [1,1,1,1,1],\
               [0,1,1,1,1],\
               [1,0,1,1,1],\
               [1,1,0,1,1]])
        False
        >>> f([[1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,1],\
               [1,1,1,1,0]])
        True
    """
    x, y = 0,0
    isValid = lambda x,y: y<len(n) and x<len(n[0]) and n[x][y] != 1
    for i in range(len(n)*len(n[0])):
        x = i%len(n)
        y = i/len(n)
        if isValid(x,y):
            break

    while not isValid(x,y):
        y += 1
        if y == len(n):
            y = 0
            x += 1
        if x == len(n[0]):
            return False # Problem is not clearly defined here
    toGo=set([(x,y)])
    visited=set()
    while toGo:
        (x,y) = toGo.pop()
        visited |= set([(x,y)])
        if isValid(x+1,y):
            toGo |= set([(x+1, y)])
        if isValid(x,y+1):
            toGo |= set([(x, y+1)])
    return len(visited)+sum(map(sum,n)) == len(n)*len(n[0])

if __name__ == "__main__":
    import doctest
    doctest.testmod()
Martin Thoma
fuente
¿Podría mover la versión de golf a la cima? Algunas personas tienen un script de usuario para este sitio que cuenta los caracteres en el primer bloque de código.
Gareth el
@Gareth: Hecho ..
Martin Thoma