Est-il convexe en L?

14

Contexte

Un polyomino est appelé L-convexe , s'il est possible de se déplacer d'une tuile à n'importe quelle autre par un chemin en forme de L, c'est-à-dire un chemin qui va dans les directions cardinales et change de direction au plus une fois. Par exemple, le polyomino de 1s dans la figure

0 0 1 1 1 0

1 1 1 1 0 0

1 1 0 0 0 0

n'est pas convexe en L, car les deux trajets en forme de L du bas à gauche 1vers le haut à droite 1contiennent 0:

0>0>1>1>1 0
^       ^
1 1 1 1 0 0
^       ^
1>1>0>0>0 0

Cependant, le polyomino de 1s dans cette figure est L-convexe:

0 1 1 1 0 0

1 1 1 1 1 1

0 1 1 0 0 0

Contribution

Votre entrée est un tableau 2D de bits au format natif de votre langue, ou en tant que chaîne délimitée par des sauts de ligne si notre langue manque de tableaux. Il est garanti d'en contenir au moins un 1.

Production

Votre sortie doit être une valeur véridique si l'ensemble de 1s est un polyomino L-convexe, et une valeur fausse dans le cas contraire. Ces sorties doivent être cohérentes: vous devez sortir la même valeur véridique pour toutes les entrées L-convexes, et la même valeur fausse pour les autres. Notez qu'un ensemble déconnecté de 1s (qui n'est pas un polyomino) entraîne une sortie fausse.

Règles et notation

Vous pouvez écrire soit un programme complet soit une fonction. Le nombre d'octets le plus bas gagne et les failles standard sont interdites.

Cas de test

Ces cas de test devraient également fonctionner si vous faites pivoter ou réfléchissez les tableaux, ou si vous ajoutez des lignes de 0s à n'importe quelle bordure.

False instances
01
10

111
101
111

1101
1111
1110

1100
1000
0011

01100
11110
01110
00110

011000
011110
001111

True instances
1

01
11

010
111
010

001
011
111

11100
11110
01100
01000

011000
011000
111100
111111
001000
Zgarb
la source
Très beau défi, je l'ai apprécié =)
flawr
À propos de l'entrée: est-ce qu'une chaîne délimitée par des sauts de ligne est autorisée, si notre langue ne manque pas de tableaux ?
edc65
@ edc65 (Désolé, je suis déconnecté de la grille depuis quelques jours.) Bien sûr, c'est autorisé aussi, c'est juste mal formulé de ma part.
Zgarb

Réponses:

6

Escargots , 45 24

&
!{\1t\1!{o\1,nf\1,!.!~

Juste après avoir publié ma solution initiale, j'ai réalisé qu'il y avait une bien meilleure façon. Le programme original a parcouru le carré formé par les chemins entre deux 1s, testant la présence d'un 0 dans chaque paire de côtés. Il devait également avoir un cas particulier pour les trajets en ligne droite. La nouvelle version commence par la téléportation de l'un 1à l'autre, et teste l'absence d'un chemin droit ou en L de 1retour au début.

feersum
la source
OMG!! Y a-t-il un interprète en ligne où nous pourrions jouer avec cela?
flawr
1
@flawr Vous pouvez le construire à partir des sources avec le code source ici .
Alex A.
6

Matlab, 182 octets

Idée: répéter pour chaque 1élément de la matrice polyomino:

  • Créez une nouvelle matrice avec seulement le 1zéro donné mais le reste.
  • pour chacun 1dans cette nouvelle matrice (répétez jusqu'à ce que plus rien ne change)
    • ajouter 1comme voisins dans la direction x s'il y a 1comme voisins dans le polynôme
  • pour chacun 1dans cette nouvelle matrice (répétez jusqu'à ce que plus rien ne change)
    • ajouter 1comme voisins dans la direction x s'il y a 1comme voisins dans le polynôme

Maintenant, 1dans la nouvelle matrice devrait couvrir tout 1dans la polynomio-matrice qui sont accessibles à partir du point de départ donné en allant d'abord dans la direction x puis dans la direction y. Maintenant, nous pouvons répéter le même processus, mais en allant d'abord dans la direction y puis dans la direction x. Maintenant, chaque1 matrice polyomino doit être atteinte en une seule fois ou les deux fois. Sinon, nous avons trouvé une position dans la matrice polynomio qui ne peut pas être atteinte à partir de toutes les autres positions par un Lchemin.

Golfé:

function r=f(a);[i,j,b]=find(a);N=nnz(i);r=1;for k=1:N;K=1:3;for l=1:2;c=b;b=a*0;b(i(k),j(k))=1;for z=1:2*N; b=conv2(b+0,K,'s')&a;if z==N;K=K';end;end;end;r=r*all(b(:)|c(:)>=a(:));end

Avec commentaires:

function r=codegolf_L_convex(a);
%a=[0,1;1,1];
[i,j,b]=find(a);%b just needs to be initialized, does not really mattter
N=nnz(i);%number of ones in the matrix
r=1;%return value
for k=1:N;%go throu all '1' in the matrix
    %expand that pixel in x dir:
    K=1:3;%convolution kernel (just three positive values needed)
    for l=1:2;%first horizontal->vertical then vertical->horizontal
        c=b;%backup for considering both runs
        b=a*0;
        b(i(k),j(k))=1; %set the seed
        for z=1:2*N;     
            b=conv2(b+0,K,'s')&a; %expand the seed horizontally (or vertically for the second half) but only within the polyomino
            if z==N;
                K=K'; %change horizontal/vertical 
            end;
        end;
    end;
    r=r*all(b(:)|c(:)>=a(:));%check whether we can really reach every point
end

Script de cas de test:

disp('all false -------------');
a=[0,1;1,0];
f(a)
a=[1,1,1;1,0,1;1,1,1];
f(a)
a=[1,1,0,1;1,1,1,1;1,1,1,0];
f(a)
a=[1,1,0,0;1,0,0,0;0,0,1,1];
f(a)
a=[0,1,1,0,0;1,1,1,1,0;0,1,1,1,0;0,0,1,1,0];
f(a)
a=[0,1,1,0,0,0;0,1,1,1,1,0;0,0,1,1,1,1];
f(a)
 disp('all true +++++++++++++');
a=[1];
f(a)
a=[0,1;1,1];
f(a)
a=[0,1,0;1,1,1;0,1,0];
f(a)
a=[0,0,1;0,1,1;1,1,1];
f(a)
a=[1,1,1,0,0;1,1,1,1,0;0,1,1,0,0;0,1,0,0,0];
f(a)
a=[0,1,1,0,0,0;0,1,1,0,0,0;1,1,1,1,0,0;1,1,1,1,1,1;0,0,1,0,0,0];
f(a)
flawr
la source
2

Javascript ES6, 290 octets

D'accord, il ne gagnera peut-être pas de prix pour sa brièveté, mais il utilise une nouvelle approche. Voir la version non golfée pour savoir comment cela fonctionne.

La preuve de cette méthode peut être trouvée dans: Automates cellulaires et systèmes complexes discrets .

L=a=>[1,0,1].every($=>(a=a[0].map((_,col)=>a.map(row=>row[col]))).map(r=>($?r.reverse():r).join``).every((r,i,b)=>r.replace(/^(0*)(1*)(0*)$|(.+)/,(_,s,m,o,e)=>(c=e)?'':!m||b[i-1]&&+b[i-1][s.length]?1:b.every((r,j)=>j<i||(c=c||!+r[l=s.length])?r.search(`0{${l}}.*0{${o.length}}`)+1:1)||'')))

Non golfé:

function L(a) {
  /* Runs three times and ensure all pass validation
   * 1: horizontally reversed
   * 2: 90 degrees rotated
   * 3: original
   *
   *     | 1:  | 2:  | 3:
   * =====================
   * 001 | 100 | 111 | 001
   * 011 | 110 | 011 | 011
   * 111 | 111 | 001 | 111
   *
   * By finding maximal rectangles with corners on all NW and NE corners
   * (separately) of a HV-convex polyomino and ensuring it doesn't enter the
   * boundaries labelled ABCD for the rectangle X below:
   *
   *   A  |         |  B
   * -----===========-----
   *      |    X    |
   * -----===========-----
   *   C  |         |  D
   *
   * The first iteration tests the NE corners and horizontal convexity.
   * The second iteration test vertical convexity.
   * The third iteration tests the NW corners.
   *
   * If all pass then the polyomino is L-convex.
   */
  return [1,0,1].every(function($){
    return (a=a[0].map((_,col)=>{
      // Transpose rows with columns
      return a.map(row=>row[col])
    })).map(row=>{
      // Join rows as strings and on odd iterations reverse them
      return ($ ? row.reverse() : row).join``
    }).every(function(row, i, b) {
      if (i == 0) console.log(b.join('\n'));
      return row.replace(/^(0*)(1*)(0*)$|(.+)/, function(_, start, middle, end, invalid) {
        // Non H-convex polyomino (0 between 1s)
        if (invalid) return '';
        // Is not a NW corner (character above is 1)
        if (!middle || b[i-1] && +b[i-1][start.length]) return 1;
        c=1;
        return b.every(function(row, j) {
          // Above or below maximal rectangle from corner
          if (j < i || !(c=c&&+row[l=start.length])) {
            // Area before and after maximal rectangle doesn't contain 1
            return row.search(`0{${l}}.*0{${end.length}}`)+1
          }
          return 1;
        }) || '';
      });
    });
  });
}
George Reith
la source
1
Ha, c'est cet article qui m'a inspiré pour ce défi!
Zgarb
@Zgarb L'article était génial et l'un des rares que j'ai pu trouver qui avait du sens pour quelqu'un qui n'est pas mathématiquement orienté.
George Reith
2

Mathematica, 129 127 octets

3>GraphDiameter@Graph[#,#<->#2&@@@Select[#~Tuples~2,!FreeQ[#-#2&@@#,0]&]]&@Position[#,1]&&{#,Thread@#}~FreeQ~{___,1,0..,1,___}&

Explication:

Premièrement, s'il y a 0entre deux 1s sur la même ligne ou colonne, le tableau n'est pas L-convexe, car nous ne pouvons pas connecter les deux 1s.

Après avoir exclu ce cas, tous les deux 1 s sur la même ligne ou colonne peuvent être connectés par un chemin droit. Nous pouvons générer un graphique, dont les sommets sont les positions de 1s dans le tableau, et les bords sont des paires de 1s sur la même ligne ou colonne. Le tableau est alors L-convexe si et seulement si le diamètre du graphique est inférieur à 3.

alephalpha
la source
1
Pouvez-vous expliquer comment cela fonctionne? Je ne vais pas voter contre le charabia que personne ne pourrait comprendre =)
flawr
Comment cela reconnaît-il les première et quatrième fausses instances (les déconnectées)?
Zgarb
1
@Zgarb Si le graphique est déconnecté, son diamètre est infini.
alephalpha
2

JavaScript (ES6) 174

En regardant la grille de cellules vides ou remplies, pour toute paire de cellules remplies, je vérifie les chemins horizontaux vers l'autre colonne de cellules (il peut y avoir 1 si les cellules sont sur la même ligne, sinon ou 2) et les chemins verticaux vers le autre ligne de cellules (il peut aussi y en avoir 1 ou 2). Si je trouve une cellule vide dans les deux chemins verticaux ou les deux chemins horizontaux, il ne peut pas y avoir de chemin en L entre les cellules.

(J'ai eu du mal à mettre en place cette explication - j'espère avoir été clair)

Testez l'exécution de l'extrait ci-dessous dans n'importe quel navigateur compatible EcmaScript 6

F=p=>!p.some((n,y)=>n.some((q,x)=>q&&p.some((o,u)=>o.some((q,t)=>{for(f=0,i=y;q&i<=u;i++)f|=!p[i][x]|2*!p[i][t];if(f<3)for(f=0,j=x;q&j<=t;j++)f|=!n[j]|2*!o[j];return f>2}))))

// TEST
console.log=(...x)=>O.innerHTML+=x+'\n'

tko = [
 [[0,1],[1,0]]
,[[1,1,1],[1,0,1],[1,1,1]]
,[[1,1,0,1],[1,1,1,1],[1,1,1,0]]
,[[1,1,0,0],[1,0,0,0],[0,0,1,1]]
,[[0,1,1,0,0],[1,1,1,1,0],[0,1,1,1,0],[0,0,1,1,0]]
,[[0,1,1,0,0,0],[0,1,1,1,1,0],[0,0,1,1,1,1]]
]
tko.forEach(t=>(console.log(t.join`\n`+`\nFalse? ${F(t)}\n`)));
tok = [
 [[1]]
,[[0,1],[1,1]]
,[[0,1,0],[1,1,1],[0,1,0]]
,[[0,0,1],[0,1,1],[1,1,1]]
,[[1,1,1,0,0],[1,1,1,1,0],[0,1,1,0,0],[0,1,0,0,0]]
,[[0,1,1,0,0,0],[0,1,1,0,0,0],[1,1,1,1,0,0],[1,1,1,1,1,1],[0,0,1,0,0,0]]
]  
tok.forEach(t=>(console.log(t.join`\n`+`\nTrue? ${F(t)}\n`)));

// LESS GOLFED

U=p=>
  !p.some((n,y)=>  
    n.some((q,x)=> 
      q && p.some((o,u)=>  
        o.some((q,t)=>{
          for(f=0,i=y; q&i<=u; i++)f|=!p[i][x]|2*!p[i][t]
          if (f<3)
            for(f=0,j=x; q&j<=t; j++)f|=!n[j]|2*!o[j]
          return f>2
        })
      )
    )
  )
<pre id=O></pre>

edc65
la source