Tentukan apakah tanah tertutup sepenuhnya oleh pagar

19

Bayangkan sebuah array dua dimensi dari nilai boolean, di mana 0s mewakili kuadrat rumput pada sebidang tanah persegi panjang dan 1s mewakili pagar.

Tulis fungsi yang menerima array 2D sebagai input dan tentukan apakah Anda dapat melakukan perjalanan dari satu area rumput ke area rumput lainnya, hanya menggunakan gerakan utara / timur / barat / selatan, tanpa berlari ke pagar.

Jika ada area rumput dalam array sepenuhnya tertutup oleh pagar (artinya Anda tidak dapat melakukan perjalanan N / E / W / S untuk mencapai setiap area rumput lain dalam array) fungsi tersebut harus mengembalikan false; jika tidak, itu harus mengembalikan true.

Di bawah ini adalah dua array sampel yang dapat Anda gunakan sebagai input, meskipun fungsi Anda harus dapat menangani tidak hanya ini tetapi setiap array 2D nilai boolean:

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)

Kode kerja terpendek menang. Saya akan memilih pemenang setelah satu minggu berlalu atau tidak ada pengiriman baru dalam 24 jam.

jawns317
sumber
Bisakah Anda juga melarang operator biner? Aku akan senang untuk melihat apa yang orang akan datang dengan.
Pierre Arlaud
Saya percaya ini sangat mirip dengan masalah USACO dari tahun lalu (musim 2012/2013). Ada beberapa test case besar yang dapat diakses di sana ...
apnorton
Apakah ukuran array selalu menjadi 5 * 5?
ProgramFOX
1
@ProgramFOX Asumsikan array bisa berapa pun tinggi, lebar apa pun. Dan tentu saja, output apa pun boolean.
jawns317
1
bagaimana dengan matriks 3X3 1 1 1; 1 0 1; 1 1 1? Ada satu sel rumput di tengah. Secara visual sel rumput di tengah sepenuhnya tertutup oleh pagar, tetapi menurut definisi Anda tidak.
emory

Jawaban:

1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2
Max Jaderberg
sumber
1
@ jawns317 Saya tidak mengerti mengapa ini adalah jawaban yang diterima. Ini bukan fungsi. Satu-satunya jawaban lain yang bukan fungsi menerima dari stdin. Yang ini bahkan tidak melakukan itu.
Tim Seguine
1
Menerima input standar dapat dilakukan seperti input('');c=bwconncomp(~ans,4);c.NumObjects<2ini. Ini akan membuatnya menjadi 45 karakter.
Dennis Jaheruddin
7

APL (39)

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

Pemakaian:

      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
sumber
9
Manfaat APL adalah tampilannya sangat mirip derau saluran sehingga tidak ada yang ingin memverifikasi itu benar.
Tim Seguine
@Tim Siapa pun dapat mengunduh juru bahasa untuk menjalankannya dan memeriksa.
Gareth
3
@ Gareth Ya, Komentar itu seharusnya menjadi lidah di pipi.
Tim Seguine
@Tim Oh, maaf. Melewatkan itu. :-(
Gareth
4

Mathematica, 60 58 karakter

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

Pemakaian:

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

Benar

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

Salah

alephalpha
sumber
2
Panjang yang samaf=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/)

Apakah mengisi banjir, kemudian memeriksa untuk melihat apakah ada 0s yang tersisa.

Gagang pintu
sumber
Sial! Jika saya belum menguji kode saya dulu saya akan lebih cepat. ;)
Tim Seguine
@Tim Tapi itu pasti salah! : P
Doorknob
3

PHP 147 202 177 165 149 byte

EDIT Saya mengalahkan hack gzip saya dengan solusi php nyata.

Masukan agak panjang .... sebagai string teks, tanpa spasi, baris dibatasi oleh baris baru. Itu mengisi dengan cs dan kemudian memeriksa untuk melihat apakah ada nol yang tersisa. Dalam loop saya gunakanexp sebagai batas atas mentah pada jumlah iterasi yang diperlukan. Saya memanfaatkan simetri untuk menangani kasus duplikat dalam kode yang lebih sedikit

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

Berikut ini adalah test case yang tidak diserap:

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

Excel VBA, 305 215 Bytes

Ya, haha VBA , tetapi sifat matriks dari masalah ini menyarankan solusi praktis di Excel mungkin menarik (Plus seseorang telah mengirimkan jawaban dalam bahasa saya yang lain!). Jelas VBA tidak akan menjadi yang paling ringkas, tapi saya pikir itu masuk akal.

Banjir ini mengisi dari titik awal yang sewenang-wenang kemudian memeriksa apakah ada "rumput" yang tersisa

R adalah rentang lembar kerja dengan 1 dan 0 yang mewakili pagar dan rumput seperti yang didefinisikan dalam masalah. Bonus, lapangan bermain tidak harus persegi panjang atau berdekatan.

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

Misalnya akan mengembalikan False. Angka nol di sebelah kanan tidak dapat dijangkau dari angka nol di sebelah kiri. Bidang yang tidak teratur tidak merusaknya.

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

Beberapa catatan tentang golf.

Saya pikir beberapa karakter bisa dipangkas jika persyaratannya terbalik untuk 1 dan 0, tetapi tidak cukup untuk membuatnya layak dibalik.

VBA menekankan pada sekelompok spasi putih (a = b vs a = b), yang tidak membantu char menghitung.

S perlu dinyatakan secara eksplisit sebagai rentang. Jika dibiarkan varian, itu berubah menjadi nilai rentang daripada rentang.

Mungkin cara yang lebih baik untuk menabrak banjir? Saya tidak bisa membuat loop yang menyimpan karakter apa pun untuk mengirimnya N / E / S / W

Sunting: rethougt kasus dasar pada mengisi banjir, berhasil memangkas sedikit dengan memeriksa apakah itu pada kasus dasar setelah rekursi daripada mencegah rekursi.

Tre
sumber
2

Python (219 byte)

Jelas bukan yang terpendek, tapi ini adalah percobaan pertama saya di sini, jadi saya bangga akan hal itu:

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)

Inputnya harus berupa String 0s & 1s di mana baris dibatasi oleh karakter baris baru (\ n).

Contoh penggunaan:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False
PsHegger
sumber
Anda dapat menggabungkan dua pernyataan terakhir jika menjadi satu dengan and, saya pikir itu menghemat beberapa karakter
Tim Seguine
Anda dapat menggunakan tabulator sebagai 8 spasi.
Konrad Borowski
2

Python (196)

Pengisian banjir standar.

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

Membawa matriks melalui STDIN dengan setiap baris dipisahkan oleh satu ruang. Misalnya "01010 01100 00000 00010 11110".

Sudharsan Mohan
sumber
2

Mathematica 53

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

Ini memanggil fungsi internal Image`MorphologicalOperationsDump`imageBinaryLabel, yang mirip dengan 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}}]

Benar

Salah

ybeltukov
sumber
1

PHP (286 karakter)

Terlalu lama, saya mungkin pergi jauh.

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-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;
}
Vereos
sumber
Ini tidak benar. Ini hanya memeriksa untuk melihat apakah tidak ada nol tunggal yang dikelilingi oleh satu. Ada cara yang lebih rumit untuk menghadang angka nol.
Tim Seguine
Tentu saja Anda benar. Saya mencari cara lain untuk menyelesaikan ini tanpa penimbunan, saya kira pencarian saya berlanjut!
Vereos
Ini hanya masalah tingkat keterjangkauan grafik, dan penimbunan banjir dalam kasus ini pada dasarnya adalah floyd-warshall tanpa secara eksplisit membuat atau mewakili grafik jangkauan. Anda dapat mencoba untuk mengekstrak grafik dan melakukan transitif penutupan sendiri, tetapi tebakan saya akan lebih lama.
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;}

Mencoba mengisi semua sel di papan, itu membuat hanya satu isi banjir yang benar.

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

Python 2.X + 3.X: 335 karakter

Golf:

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

Tidak Disatukan:

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
sumber
Bisakah Anda memindahkan versi golf ke atas? Beberapa orang memiliki skrip pengguna untuk situs ini yang menghitung karakter di blok kode pertama.
Gareth
@ Gareth: Selesai ..
Martin Thoma