Determinar se a terra é totalmente cercada por cercas

19

Imagine uma matriz bidimensional de valores booleanos, onde os 0s representam quadrados de grama em um terreno retangular e os 1s representam cercas.

Escreva uma função que aceite a matriz 2D como entrada e determine se você pode viajar de qualquer área de grama para qualquer outra área de grama, usando apenas movimentos norte / leste / oeste / sul, sem entrar em uma cerca.

Se qualquer área de grama na matriz estiver totalmente cercada por cercas (o que significa que você não pode viajar N / E / W / S para alcançar todas as outras áreas de grama na matriz) a função deve retornar false; caso contrário, ele deve retornar true.

Abaixo estão duas matrizes de amostra que você pode usar como entradas, embora sua função possa manipular não apenas essas, mas qualquer 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)

O menor código de trabalho vence. Eu escolherei o vencedor depois que uma semana se passou ou não houve novos envios dentro de 24 horas.

jawns317
fonte
Você também pode proibir operadores binários? Eu amo ver o que as pessoas iriam chegar a.
Pierre Arlaud
Eu acredito que isso é muito semelhante a um problema da USACO do ano passado (temporada 2012/2013). Há alguns casos de teste enormes que podem ser acessados lá ...
apnorton
O tamanho da matriz sempre será 5 * 5?
ProgramFOX
11
@ProgramFOX Suponha que o array possa ter qualquer altura ou largura. E claro, produza algo booleano.
precisa saber é o seguinte
11
e a matriz 3X3 1 1 1; 1 0 1; 1 1 1? Há uma célula de grama no centro. Visualmente, a célula de grama no centro é totalmente cercada por cercas, mas, por sua definição, não é.
Emory

Respostas:

1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2
Max Jaderberg
fonte
11
@ jawns317 Não vejo por que essa é a resposta aceita. Isso não é uma função. A única outra resposta que não é uma função aceita do stdin. Este nem faz isso.
Tim Seguine
11
Aceitar entrada padrão pode ser feito como tal. input('');c=bwconncomp(~ans,4);c.NumObjects<2Isso daria 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
fonte
9
O benefício do APL é que ele se parece tanto com o ruído da linha que ninguém deseja verificar se está correto.
Tim Seguine
@ Tim Qualquer pessoa pode baixar um intérprete para executá-lo e verificar.
Gareth
3
@ Gareth Sim, o comentário deveria ser de língua na bochecha.
Tim Seguine
@ Tim Oh desculpe. Perdeu isso. :-(
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}}]

Verdade

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

alefalpha
fonte
2
Mesmo comprimentof=Max@WatershedComponents[Image@#,CornerNeighbors->1>2]<2&
Dr. belisarius
3

Ruby, 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/)

Faz um preenchimento e depois verifica se há 0s restantes.

Maçaneta da porta
fonte
Droga! Se não tivesse testado meu código primeiro, teria sido mais rápido. ;)
Tim Seguine
@ Tim Mas então teria sido errado! : P
Maçaneta da porta
3

PHP 147 202 177 165 149 bytes

EDIT Bati meu gzip hack com uma solução php real.

Um pouco longo .... insira como uma sequência de texto, sem espaços, linhas delimitadas por novas linhas. Ele é preenchido com cs e, em seguida, verifica se há zeros restantes. No loop, eu uso expcomo limite superior bruto no número de iterações necessárias. Aproveito a simetria para lidar com os casos duplicados em 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');}

Aqui está um caso de teste não destruído:

<?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
fonte
3

Excel VBA, 305 215 bytes

Sim, haha VBA , mas a natureza da matriz do problema sugere uma solução prática no Excel pode ser interessante (além disso, alguém já enviou uma resposta em meus outros idiomas!). Obviamente, o VBA não será o mais sucinto, mas acho que é razoável.

Essa inundação é preenchida a partir de um ponto de partida arbitrário e verifica se há alguma "grama"

R é um intervalo de planilha com 1 e 0 representando as cercas e a grama, conforme definido no problema. Bônus, o campo de jogo não precisa ser retangular nem contíguo.

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

Por exemplo, retornaria False. Os zeros à direita não podem ser alcançados a partir dos zeros à esquerda. O campo irregular não o quebra.

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

Algumas notas sobre o golfe.

Eu acho que alguns caracteres podem ser cortados se o requisito for invertido em relação a 1 e 0, mas não o suficiente para fazer com que valha a pena inverter.

O VBA insiste em muitos espaços em branco (a = b vs a = b), o que não ajuda na contagem de caracteres.

S precisa ser declarado explicitamente como um intervalo. Se for deixada uma variante, ela se transformará em um valor de intervalo, e não em um intervalo.

Talvez uma maneira melhor de ramificar o dilúvio? Não consegui criar um loop que salvasse caracteres para enviá-lo N / E / S / W

Edit: rethougt o caso base no preenchimento de inundação, conseguiu aparar bastante verificando se está em um caso base após a recursão, em vez de impedir a recursão.

Tre
fonte
2

Python (219 bytes)

Definitivamente não é o mais curto, mas é a minha primeira tentativa aqui, por isso estou orgulhoso disso:

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)

Sua entrada deve ser uma String de 0s e 1s, onde as linhas são delimitadas por um caractere de nova linha (\ n).

Exemplo de uso:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False
PsHegger
fonte
você pode combinar os dois últimos se as declarações em um com and, eu acho que salva alguns caracteres
Tim Seguine
Você pode usar o tabulador como 8 espaços.
precisa saber é o seguinte
2

Python (196)

Enchimento padrão.

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

Leva a matriz através de STDIN com cada linha separada por um único espaço. Por exemplo "01010 01100 00000 00010 11110".

Sudharsan Mohan
fonte
2

Mathematica 53

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

Chama a função interna Image`MorphologicalOperationsDump`imageBinaryLabel, que é semelhante 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}}]

Verdade

Falso

ybeltukov
fonte
1

PHP (286 caracteres)

Muito tempo, eu provavelmente fui o longo caminho.

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

Não-golfe:

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
fonte
Isto não está correto. Ele só verifica se não há zeros únicos cercados por um. Existem maneiras mais complicadas de isolar zeros.
Tim Seguine
Claro que voce esta certo. Eu estava procurando outra maneira de resolver isso sem enchentes, acho que minha pesquisa continua!
Vereos
É apenas um problema de acessibilidade de gráfico e, nesse caso, o floodfill é basicamente o floyd-warshall sem criar ou representar explicitamente o gráfico de acessibilidade. Você pode tentar extrair o gráfico e fazer o fechamento transitivo, mas meu palpite é que será mais longo.
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;}

Ele tenta preencher todas as células da placa de inundação, e faz com que apenas um preenchimento de inundação retorne verdadeiro.

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
fonte
0

Python 2.X + 3.X: 335 chararcters

Golfe:

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

Ungolfed:

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
fonte
Você poderia mover a versão golfada para o topo? Algumas pessoas têm um script de usuário para este site que conta os caracteres no primeiro bloco de código.
Gareth
@Gareth: Done ..
Martin Thoma