Determina se la terra è completamente chiusa da recinzioni


19

Immagina una matrice bidimensionale di valori booleani, in cui gli 0 rappresentano quadrati di erba su un appezzamento di terra rettangolare e gli 1 rappresentano recinzioni.

Scrivi una funzione che accetta l'array 2D come input e determina se puoi viaggiare da una qualsiasi area di erba a qualsiasi altra area di erba, usando solo i movimenti nord / est / ovest / sud, senza incorrere in una recinzione.

Se qualsiasi area di erba nell'array è completamente chiusa da recinzioni (il che significa che non è possibile viaggiare N / E / W / S per raggiungere ogni altra area di erba nell'array) la funzione dovrebbe restituire false; altrimenti, dovrebbe tornare vero.

Di seguito sono riportati due array di esempio che è possibile utilizzare come input, sebbene la propria funzione dovrebbe essere in grado di gestire non solo questi ma qualsiasi array 2D di valori booleani:

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)

Vince il codice di lavoro più breve. Prenderò il vincitore dopo che è trascorsa una settimana o non ci sono stati nuovi invii entro 24 ore.


Puoi anche vietare agli operatori binari? Mi piacerebbe piace vedere quello che la gente sarebbe venuto su con.
Pierre Arlaud,

Credo che questo sia molto simile a un problema USACO dell'anno scorso (stagione 2012/2013). Ci sono alcuni enormi casi di test a cui è possibile accedere lì ...
apnorton,

Le dimensioni dell'array saranno sempre 5 * 5?
Programma FOX

1
@ProgramFOX Supponiamo che l'array possa avere qualsiasi altezza, qualsiasi larghezza. E sicuramente, produce qualcosa di booleano.
jawns317,

1
che dire della matrice 3X3 1 1 1; 1 0 1; 1 1 1? C'è una cella d'erba al centro. Visivamente la cella d'erba al centro è completamente chiusa da recinzioni, ma per definizione non lo è.
emory

Risposte:


1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2

1
@ jawns317 Non vedo perché questa è la risposta accettata. Questa non è una funzione. L'unica altra risposta che non è una funzione accetta da stdin. Questo non lo fa nemmeno.
Tim Seguine,

1
L'accettazione dell'input standard potrebbe essere eseguita come tale. input('');c=bwconncomp(~ans,4);c.NumObjects<2Ciò renderebbe 45 caratteri.
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

9
Il vantaggio di APL è che assomiglia molto al rumore di linea che nessuno vuole verificare che sia corretto.
Tim Seguine,

@Tim Chiunque può scaricare un interprete per eseguirlo e verificarlo.
Gareth,

3
@Gareth Sì, il commento doveva essere ironico.
Tim Seguine,

@ Tim Oh scusa. Perso quello. :-(
Gareth

4

Mathematica, 60 58 caratteri

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

Vero

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


2
Stessa lunghezzaf=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/)

Effettua un riempimento, quindi verifica se sono rimasti 0.


Dannazione! Se non avessi prima testato il mio codice sarei stato più veloce. ;)
Tim Seguine,

@Tim Ma allora sarebbe stato sbagliato! : P
Maniglia della porta

3

PHP 147 202 177 165 149 byte

EDIT Ho battuto il mio hack gzip con una vera soluzione php.

Un po 'lungo .... input come stringa di testo, senza spazi, righe delimitate da newline. Si riempie di cs e quindi controlla se sono rimasti degli zeri. Nel ciclo uso expcome limite superiore grezzo il numero di iterazioni richieste. Approfitto della simmetria per gestire i casi duplicati in meno codice

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

Ecco un caso di prova non golfato:

<?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));

3

Excel VBA, 305 215 byte

Sì, haha VBA , ma la natura matriciale del problema suggerisce che una soluzione pratica in Excel potrebbe essere interessante (inoltre qualcuno ha già inviato una risposta nelle mie altre lingue!). Ovviamente VBA non sarà il più succinto, ma penso che sia ragionevole.

Questa inondazione si riempie da un punto di partenza arbitrario, quindi controlla se è rimasta qualche "erba"

R è un intervallo di fogli di lavoro con 1 e 0 che rappresentano i recinti e l'erba come definito nel problema. Bonus, il campo di gioco non deve essere rettangolare o neppure contiguo.

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

Ad esempio, restituirebbe False. Gli zeri a destra non sono raggiungibili dagli zeri a sinistra. Il campo irregolare non 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

Alcune note sul golf.

Penso che alcuni caratteri potrebbero essere tagliati se il requisito fosse invertito rispetto a 1 e 0, ma non abbastanza per renderlo degno di essere invertito.

VBA insiste su un mucchio di spazi bianchi (a = b vs a = b), che non aiuta il conteggio dei caratteri.

S deve essere esplicitamente dichiarato come intervallo. Se viene lasciata una variante, si trasforma in un valore di intervallo piuttosto che in un intervallo.

Forse un modo migliore per ramificare l'alluvione? Non sono riuscito a creare un loop che ha salvato alcun carattere per inviarlo N / E / S / W

Modifica: riprogrammare il caso di base sul riempimento dell'inondazione, è riuscito a tagliare un po 'fuori controllando se si trova in un caso di base dopo la ricorsione piuttosto che impedire la ricorsione.


2

Python (219 byte)

Sicuramente non il più breve, ma è il mio primo tentativo qui, quindi ne vado orgoglioso:

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)

Il suo input dovrebbe essere una stringa di 0 e 1 in cui le righe sono delimitate da un carattere di nuova riga (\ n).

Esempio di utilizzo:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False

puoi unire le ultime due dichiarazioni if ​​in una and, penso che risparmi alcuni caratteri
Tim Seguine,

Puoi usare tabulator come 8 spazi.
Konrad Borowski il

2

Python (196)

Riempimento standard.

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

Porta la matrice tramite STDIN con ogni riga separata da un singolo spazio. Ad esempio "01010 01100 00000 00010 11110".


2

Mathematica 53

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

Chiama la funzione interna Image`MorphologicalOperationsDump`imageBinaryLabel, che è simile 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}}]

Vero

falso


1

PHP (286 caratteri)

Troppo a lungo, probabilmente ho fatto molta strada.

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

Non-giocato a golf:

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

Questo non è corretto Controlla solo se non ci sono singoli zeri che sono circondati da uno. Esistono modi più complicati per bloccare gli zeri.
Tim Seguine,

Certo che hai ragione. Stavo cercando un altro modo per risolverlo senza inondazioni, immagino che la mia ricerca continui!
Vereos,

È solo un problema di raggiungibilità del grafico e in questo caso il processo di inondazione è sostanzialmente floyd-warshall senza creare o rappresentare esplicitamente il grafico di raggiungibilità. Potresti provare ad estrarre il grafico e fare tu stesso la chiusura transitiva, ma suppongo che sarà più lungo.
Tim Seguine,

1

C #, 235 byte

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

Cerca di riempire tutte le celle della scheda, rende vero un solo riempimento.

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

0

Python 2.X + 3.X: 335 caratteri

golfed:

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

Potresti spostare la versione golfata verso l'alto? Alcune persone hanno uno script utente per questo sito che conta i caratteri nel primo blocco di codice.
Gareth,

@Gareth: Fatto ..
Martin Thoma,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.