Déterminer si le terrain est entièrement clos de clôtures

19

Imaginez un tableau bidimensionnel de valeurs booléennes, où les 0 représentent des carrés d'herbe sur un terrain rectangulaire et les 1 représentent des clôtures.

Écrivez une fonction qui accepte le tableau 2D en entrée et détermine si vous pouvez vous déplacer d'une zone d'herbe à une autre zone d'herbe, en utilisant uniquement les mouvements nord / est / ouest / sud, sans tomber dans une clôture.

Si une zone d'herbe dans le tableau est entièrement entourée de clôtures (ce qui signifie que vous ne pouvez pas voyager N / E / W / S pour atteindre toutes les autres zones d'herbe du tableau), la fonction doit retourner false; sinon, cela devrait retourner vrai.

Vous trouverez ci-dessous deux exemples de tableaux que vous pouvez utiliser comme entrées, bien que votre fonction devrait être capable de gérer non seulement ces tableaux, mais tout tableau 2D de valeurs booléennes:

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)

Le code de travail le plus court gagne. Je choisirai le gagnant après une semaine ou s'il n'y a eu aucune nouvelle soumission dans les 24 heures.

jawns317
la source
Pouvez-vous également interdire les opérateurs binaires? J'aime voir ce que les gens viennent avec.
Pierre Arlaud
Je crois que cela ressemble beaucoup à un problème USACO de l'année dernière (saison 2012/2013). Il y a d'énormes cas de test qui peuvent être consultés là-bas ...
apnorton
La taille du tableau sera-t-elle toujours 5 * 5?
ProgramFOX
1
@ProgramFOX Supposons que le tableau puisse avoir n'importe quelle hauteur, n'importe quelle largeur. Et bien sûr, sortez n'importe quoi booléen.
jawns317
1
qu'en est-il de la matrice 3X3 1 1 1; 1 0 1; 1 1 1? Il y a une cellule d'herbe au centre. Visuellement, l'herbe au centre est entièrement entourée de clôtures, mais selon votre définition, ce n'est pas le cas.
emory

Réponses:

1

Matlab 45

input('');c=bwconncomp(~ans,4);c.NumObjects<2
Max Jaderberg
la source
1
@ jawns317 Je ne vois pas pourquoi c'est la réponse acceptée. Ce n'est pas une fonction. La seule autre réponse qui n'est pas une fonction accepte de stdin. Celui-là ne fait même pas ça.
Tim Seguine
1
L'acceptation d'une entrée standard pourrait être effectuée en tant que telle. input('');c=bwconncomp(~ans,4);c.NumObjects<2Cela ferait 45 caractères.
Dennis Jaheruddin
7

APL (39)

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

Usage:

      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
la source
9
L'avantage de l'APL est qu'il ressemble tellement au bruit de ligne que personne ne veut vérifier qu'il est correct.
Tim Seguine
@Tim N'importe qui peut télécharger un interprète pour l'exécuter et vérifier.
Gareth
3
@Gareth Ouais, le commentaire était censé être ironique.
Tim Seguine
@Tim Oh désolé. Ça m'a manqué. :-(
Gareth
4

Mathematica, 60 58 caractères

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

Usage:

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

Vrai

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

Faux

alephalpha
la source
2
Même duréef=Max@WatershedComponents[Image@#,CornerNeighbors->1>2]<2&
Dr belisarius
3

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

Effectue un remplissage, puis vérifie s'il reste des 0.

Poignée de porte
la source
Zut! Si je n'avais pas testé mon code en premier, j'aurais été plus rapide. ;)
Tim Seguine
@Tim Mais alors ça aurait été faux! : P
Poignée de porte
3

PHP 147 202 177 165 149 octets

EDIT J'ai battu mon hack gzip avec une vraie solution php.

Un peu long .... entrée sous forme de chaîne de texte, pas d'espaces, lignes délimitées par des retours à la ligne. Il se remplit de cs et vérifie ensuite s'il reste des zéros. Dans la boucle, j'utilise expcomme une limite supérieure brute sur le nombre d'itérations nécessaires. Je profite de la symétrie pour gérer les doublons en moins de code

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

Voici un cas de test non 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
la source
3

Excel VBA, 305 215 octets

Oui, haha VBA , mais la nature matricielle du problème suggère qu'une solution pratique dans Excel pourrait être intéressante (De plus, quelqu'un a déjà soumis une réponse dans mes autres langues!). Évidemment, VBA ne sera pas le plus succinct, mais je pense que c'est raisonnable.

Cette inondation se remplit à partir d'un point de départ arbitraire puis vérifie s'il reste de l'herbe

R est une plage de feuille de calcul avec 1 et 0 représentant les clôtures et l'herbe telles que définies dans le problème. Bonus, le terrain de jeu n'a pas besoin d'être rectangulaire ou même contigu.

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

Par exemple, renverrait False. Les zéros de droite ne sont pas accessibles depuis les zéros de gauche. Le champ irrégulier ne le brise pas.

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

Quelques notes sur le golf.

Je pense que certains caractères pourraient être coupés si l'exigence était inversée en ce qui concerne 1 et 0, mais pas assez pour que cela vaille la peine d'être inversé.

VBA insiste sur un tas d'espace (a = b vs a = b), ce qui n'aide pas le nombre de caractères.

S doit être explicitement déclaré comme une plage. S'il ne reste qu'une variante, il se transforme en valeur de plage plutôt qu'en plage.

Peut-être une meilleure façon de limiter l'inondation? Je n'ai pas pu trouver une boucle qui a sauvé tous les caractères pour l'envoyer N / E / S / W

Edit: rethougt le cas de base sur le remplissage d'inondation, a réussi à couper un peu en vérifiant s'il se trouve dans un cas de base après la récursivité plutôt que d'empêcher la récursivité.

Tre
la source
2

Python (219 octets)

Ce n'est certainement pas le plus court, mais c'est mon premier essai ici, donc j'en suis fier:

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)

Son entrée doit être une chaîne de 0 et de 1 où les lignes sont délimitées par un caractère de nouvelle ligne (\ n).

Exemple d'utilisation:

>>> f("00000\n01000\n01111\n00000\n00011")
True
>>> f("01010\n01100\n00000\n00010\n11110")
False
PsHegger
la source
vous pouvez combiner les deux dernières instructions if en une seule and, je pense que cela permet d'économiser certains caractères
Tim Seguine
Vous pouvez utiliser le tabulateur comme 8 espaces.
Konrad Borowski
2

Python (196)

Remplissage standard contre les inondations.

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

Prend la matrice via STDIN avec chaque ligne séparée par un seul espace. Par exemple "01010 01100 00000 00010 11110".

Sudharsan Mohan
la source
2

Mathematica 53

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

Il appelle la fonction interne Image`MorphologicalOperationsDump`imageBinaryLabel, qui est similaire à 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}}]

Vrai

Faux

ybeltukov
la source
1

PHP (286 caractères)

Beaucoup trop longtemps, j'ai probablement fait le long chemin.

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
la source
Ce n'est pas correct. Il vérifie uniquement s'il n'y a pas de zéros isolés entourés de zéros. Il existe des moyens plus compliqués de séparer les zéros.
Tim Seguine
Bien sûr, vous avez raison. Je cherchais un autre moyen de résoudre ce problème sans remplissage, je suppose que ma recherche continue!
Vereos
Il s'agit simplement d'un problème d'accessibilité aux graphes, et dans ce cas, l'inondation est essentiellement floyd-warshall sans créer ou représenter explicitement le graphe d'accessibilité. Vous pouvez essayer d'extraire le graphique et de faire la fermeture transitive vous-même, mais je suppose que ce sera plus long.
Tim Seguine
1

C #, 235 octets

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

Il essaie de remplir chaque cellule de la carte, il ne fait qu'un seul remplissage d'inondation renvoie true.

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
la source
0

Python 2.X + 3.X: 335 caractères

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

Non 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
la source
Pourriez-vous déplacer la version golfée vers le haut? Certaines personnes ont un script utilisateur pour ce site qui compte les caractères du premier bloc de code.
Gareth
@Gareth: Fait ..
Martin Thoma