Ustal, czy teren jest w całości ogrodzony płotami

19

Wyobraź sobie dwuwymiarową tablicę wartości boolowskich, gdzie 0 oznaczają kwadraty trawy na prostokątnej działce, a 1 oznaczają ogrodzenie.

Napisz funkcję, która akceptuje tablicę 2D jako dane wejściowe i określa, czy możesz podróżować z dowolnego obszaru trawy do dowolnego innego obszaru trawy, używając tylko ruchów północ / wschód / zachód / południe, bez wpadania na płot.

Jeśli jakikolwiek obszar trawy w tablicy jest całkowicie otoczony płotami (co oznacza, że ​​nie można podróżować N / E / W / S, aby dotrzeć do każdego innego obszaru trawy w tablicy), funkcja powinna zwrócić wartość false; w przeciwnym razie powinien zwrócić wartość true.

Poniżej znajdują się dwie przykładowe tablice, których możesz użyć jako danych wejściowych, chociaż twoja funkcja powinna być w stanie obsłużyć nie tylko te, ale dowolną tablicę 2D wartości logicznych:

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)

Wygrywa najkrótszy działający kod. Wybiorę zwycięzcę po upływie tygodnia lub nowych zgłoszeń w ciągu 24 godzin.

jawns317
źródło
Czy możesz również zabronić operatorom binarnym? Chciałbym kochać , aby zobaczyć, co ludzie wymyślić.
Pierre Arlaud
Uważam, że jest to bardzo podobne do problemu USACO z ubiegłego roku (sezon 2012/2013). Istnieje kilka ogromnych przypadków testowych, do których można uzyskać dostęp ...
apnorton
Czy rozmiar tablicy zawsze będzie wynosił 5 * 5?
ProgramFOX
1
@ProgramFOX Załóżmy, że tablica może mieć dowolną wysokość, dowolną szerokość. I jasne, wypisz coś logicznego.
jawns317
1
co z matrycą 3X3 1 1 1; 1 0 1; 1 1 1? W centrum znajduje się jedna komórka trawiasta. Wizualnie komórka trawy w środku jest całkowicie ogrodzona płotami, ale z twojej definicji tak nie jest.
emory

Odpowiedzi:

1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2
Max Jaderberg
źródło
1
@ jawns317 Nie rozumiem, dlaczego jest to akceptowana odpowiedź. To nie jest funkcja. Jedyna inna odpowiedź, która nie jest funkcją, przyjmuje od standardowego wejścia. Ten nawet tego nie robi.
Tim Seguine,
1
Zaakceptowanie standardowego wprowadzania danych może być wykonane jako takie. input('');c=bwconncomp(~ans,4);c.NumObjects<2To daje 45 znaków.
Dennis Jaheruddin
7

APL (39)

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

Stosowanie:

      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
źródło
9
Zaletą APL jest to, że wygląda tak podobnie do szumu linii, że nikt nie chce sprawdzić, czy jest poprawny.
Tim Seguine
@Tim Każdy może pobrać tłumacza, aby go uruchomić i sprawdzić.
Gareth
3
@Gareth Tak, komentarz miał być język w policzek.
Tim Seguine
@ Tim Och przepraszam. Przegapiłem to. :-(
Gareth
4

Mathematica, 60 58 znaków

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

Stosowanie:

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

Prawdziwe

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

Fałszywy

alephalpha
źródło
2
Ta sama długośćf=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/)

Wypełnia zalanie, a następnie sprawdza, czy pozostały zera.

Klamka
źródło
Cholera! Gdybym nie przetestował najpierw kodu, byłbym szybszy. ;)
Tim Seguine
@Tim Ale to byłoby źle! : P
Klamka
3

PHP 147 202 177 165 149 bajtów

EDYCJA Pobiłem swój hack gzip z prawdziwym rozwiązaniem php.

Trochę długi .... wejście jako ciąg tekstowy, bez spacji, wiersze oddzielone znakami nowej linii. Powodzi wypełnia się cs, a następnie sprawdza, czy pozostały zera. W pętli używam expjako surowej górnej granicy liczby wymaganych iteracji. Korzystam z symetrii do obsługi zduplikowanych przypadków przy mniejszym kodzie

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

Oto przypadek testowy bez golfa:

<?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
źródło
3

Excel VBA, 305 215 bajtów

Tak, haha VBA , ale macierzowy charakter problemu sugeruje praktyczne rozwiązanie w Excelu (plus ktoś już przesłał odpowiedź w moich innych językach!). Oczywiście VBA nie będzie najbardziej zwięzły, ale myślę, że to rozsądne.

Ta powódź wypełnia się z dowolnego punktu początkowego, a następnie sprawdza, czy pozostała „trawa”

R jest zakresem arkusza z zerami i zerami reprezentującymi ogrodzenia i trawę zgodnie z definicją problemu. Premia, pole gry nie musi być prostokątne ani nawet ciągłe.

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

Na przykład zwróci wartość False. Zera po prawej stronie nie mogą być osiągnięte z zer po lewej stronie. Nieregularne pole go nie łamie.

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

Kilka uwag na temat gry w golfa.

Myślę, że niektóre znaki mogą zostać przycięte, jeśli wymaganie zostało odwrócone w stosunku do 1 i 0, ale niewystarczająco, aby warto było odwrócić.

VBA nalega na kilka białych znaków (a = b vs a = b), co nie pomaga w liczeniu znaków.

S należy wyraźnie zadeklarować jako zakres. Jeśli pozostawia wariant, zmienia się w wartość zakresu, a nie w zakres.

Może lepszy sposób na rozgałęzienie powodzi? Nie mogłem wymyślić pętli, która oszczędziłaby dowolne znaki, aby wysłać ją N / E / S / W

Edycja: ponownie przeanalizuj skrzynkę podstawową przy wypełnieniu powodziowym, udało się ją nieco przyciąć, sprawdzając, czy jest ona w skrzynce podstawowej po rekurencji, zamiast zapobiegać rekurencji.

Tre
źródło
2

Python (219 bajtów)

Zdecydowanie nie najkrótszy, ale to moja pierwsza próba tutaj, więc jestem z tego dumny:

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)

Dane wejściowe powinny być ciągiem zer i jedynek, w których wiersze są rozdzielane znakiem nowej linii (\ n).

Przykładowe użycie:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False
PsHegger
źródło
możesz połączyć dwa ostatnie zdania if w jedno and, myślę, że to oszczędza trochę znaków
Tim Seguine
Możesz użyć tabulatora jako 8 spacji.
Konrad Borowski
2

Python (196)

Standardowe wypełnienie zalewowe.

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

Prowadzi macierz przez STDIN, a każdy wiersz jest oddzielony pojedynczą spacją. Na przykład „01010 01100 00000 00010 11110”.

Sudharsan Mohan
źródło
2

Mathematica 53

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

Wywołuje funkcję wewnętrzną Image`MorphologicalOperationsDump`imageBinaryLabel, która jest podobna do 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}}]

Prawdziwe

Fałszywy

Ybeltukov
źródło
1

PHP (286 znaków)

O wiele za długo, prawdopodobnie przeszedłem długą drogę.

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

Nie golfa:

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
źródło
To nie jest poprawne Sprawdza tylko, czy nie ma pojedynczych zer otoczonych jedynkami. Istnieją bardziej skomplikowane sposoby eliminowania zer.
Tim Seguine
Oczywiście masz rację. Szukałem innego sposobu rozwiązania tego problemu bez zalewania, chyba moje wyszukiwanie trwa!
Vereos
Jest to po prostu problem z osiągalnością grafu, a wypełnienie w tym przypadku jest w zasadzie Floyd-Warshall bez wyraźnego tworzenia lub reprezentowania wykresu osiągalności. Możesz spróbować wyodrębnić wykres i samodzielnie wykonać przejście przechodnie, ale domyślam się, że będzie on dłuższy.
Tim Seguine
1

C #, 235 bajtów

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

Próbuje zalać każdą komórkę na planszy, sprawia, że ​​tylko jeden zwrot wypełnienia jest prawdziwy.

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
źródło
0

Python 2.X + 3.X: 335 znaków

Gra w golfa:

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

Nie golfowany:

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
źródło
Czy możesz przenieść wersję golfa na szczyt? Niektóre osoby mają skrypt użytkownika dla tej witryny, który zlicza znaki w pierwszym bloku kodu.
Gareth,
@Gareth: Gotowe ..
Martin Thoma