Où va ce serpent?


35

Ecrivez une fonction (en utilisant le moins d'octets possible) qui prend un tableau bidimensionnel de n'importe quel nombre de colonnes et de lignes dans lequel:

  • 0 représente un bloc vide,
  • 1 représente le bloc de serpent.

La fonction doit renvoyer le nombre de chemins possibles empruntés par le serpent.

Exemple 1:

Contribution:

[
  [1,1,1,1,1],
  [0,0,0,0,1],
  [0,0,0,0,1],
]

Sortie: 2

Dans l'exemple ci-dessus, la fonction retournera 2 car la réponse est l'une des suivantes:

entrez la description de l'image ici

Exemple 2:

Contribution:

[
  [1,1,1,1],
  [0,0,1,1],
  [0,0,1,1],
]

Sortie: 6

Dans cet exemple, la fonction retournera 6car la réponse est l'une des suivantes:

entrez la description de l'image ici

Remarque:

Lors de l'évaluation de l'entrée, vous pouvez supposer que:

  • Les tableaux représentant les colonnes auront toujours les mêmes tailles (les tableaux sont donc rectangulaires);
  • Il existe au moins un chemin valide.
  • Le serpent ne peut pas traverser les bords (comme cela peut arriver dans certaines versions de serpent);
  • Le serpent aura toujours au moins 2 blocs;
  • Le serpent ne peut pas se déplacer en diagonale;
  • Les chemins sont dirigés. (Donc, deux chemins se terminant à des positions différentes, mais qui ont exactement la même apparence ne sont pas identiques, cela fera le total)

13
Bienvenue chez PPCG! Beau premier défi.
Laikoni

5
Remarque mineure: "Il y aura toujours au moins une ligne et une colonne" est redondant, étant donné que le serpent aura toujours au moins 2 blocs.
Stewie Griffin

2
Cas de test suggérés: celui donné par @StewieGriffin et [[0,0,1,1],[0,0,1,1],[0,0,1,1]]. La plupart des réponses donnent 16, mais on en donne 15.
Kevin Cruijssen

2
Il semble que tout le monde jusqu’à présent (y compris moi-même) ait supposé que 2 chemins se terminant à des positions différentes mais qui ont exactement la même apparence ne sont pas identiques. Je pense que cela doit être explicitement spécifié.
Arnauld

2
@Arnauld - c'est vrai. Deux chemins se terminant à des positions différentes mais ayant exactement la même apparence ne sont pas le même chemin , cela va ajouter au total. Dans votre exemple, le total devrait être de 16 si je ne me trompe pas - je ne peux pas calculer avec précision pour l'instant mais vous obtenez le point
Adelin

Réponses:


11

Wolfram Language (Mathematica) , 16 + 83 = 99 octets

Déclaration d'importation de bibliothèque (16 octets):

<<Combinatorica`

Corps de la fonction actuelle (83 octets):

Length@HamiltonianCycle[MakeGraph[#~Position~1~Join~{1>0},##||Norm[#-#2]==1&],All]&

Essayez-le en ligne!


Notez que la question demande simplement le nombre de chemins hamiltonien dans le graphique.

Cependant, pour une raison quelconque, la HamiltonianPathfonction ne fonctionne pas vraiment avec un graphe dirigé ( exemple ). J'ai donc utilisé la solution de contournement décrite dans cette question Mathematica.SE :

  • Ajoutez un sommet (appelé True) connecté à tous les autres sommets.
  • Comptez le nombre de cycles hamiltonien sur le graphique obtenu.

Le graphique est construit en utilisant MakeGraph(ennuyeusement, il n'y a pas d'intégré directement équivalent), en utilisant la fonction booléenne ##||Norm[#-#2]==1&, qui retourne Truesi et seulement si l'un des arguments est Trueou si la distance entre les deux sommets l'est 1.


Tr[1^x]ne peut pas être utilisé à la place de Length@x, <2ni à la place de ==1.


HamiltonianPathpeut être utilisé si le graphique est non dirigé, avec le corps de la fonction prend 84 octets (exactement 1 octet de plus que la soumission actuelle):

Length@HamiltonianPath[MakeGraph[#~Position~1,Norm[#-#2]==1&,Type->Undirected],All]&

Essayez-le en ligne!


10

JavaScript (ES6), 154 134 octets

m=>m.map((r,Y)=>r.map(g=(_,x,y,r=m[y=1/y?y:Y])=>r&&r[x]&&[-1,0,1,2].map(d=>r[r[x]=0,/1/.test(m)?g(_,x+d%2,y+~-d%2):++n,x]=1)),n=0)|n/4

Essayez-le en ligne!

Comment?

Méthode

En commençant par chaque cellule possible, nous inondons la matrice, effaçant toutes les cellules sur notre chemin. Chaque fois que la matrice ne contient plus de 1 , on incrémente le nombre n de chemins possibles.

Chaque chemin valide est compté 4 fois en raison de la direction choisie dans la dernière cellule, ce qui importe peu. Le résultat final est donc n / 4 .

Fonction récursive

Au lieu d'appeler la fonction récursive g () à partir du rappel de la deuxième carte () comme ceci ...

m=>m.map((r,y)=>r.map((_,x)=>(g=(x,y,r=m[y])=>...g(x+dx,y+dy)...)(x,y)))

... nous définissons la fonction récursive g () directement comme le rappel de map () :

m=>m.map((r,Y)=>r.map(g=(_,x,y,r=m[y=1/y?y:Y])=>...g(_,x+dx,y+dy)...))

Malgré la formule plutôt longue y=1/y?y:Y nécessaire pour définir la valeur initiale de y , cela économise globalement 2 octets.

Code commenté

m =>                           // given the input matrix m[][]
  m.map((r, Y) =>              // for each row r[] at position Y in m[][]:
    r.map(g = (                //   for each entry in r[], use g() taking:
      _,                       //     - the value of the cell (ignored)
      x,                       //     - the x coord. of this cell
      y,                       //     - either the y coord. or an array (1st iteration),
                               //       in which case we'll set y to Y instead
      r = m[y = 1 / y ? y : Y] //     - r = the row we're currently located in
    ) =>                       //       (and update y if necessary)
      r && r[x] &&             //     do nothing if this cell doesn't exist or is 0
      [-1, 0, 1, 2].map(d =>   //     otherwise, for each direction d,
        r[                     //     with -1 = West, 0 = North, 1 = East, 2 = South:
          r[x] = 0,            //       clear the current cell
          /1/.test(m) ?        //       if the matrix still contains at least one '1':
            g(                 //         do a recursive call to g() with:
              _,               //           a dummy first parameter (ignored)
              x + d % 2,       //           the new value of x
              y + ~-d % 2      //           the new value of y
            )                  //         end of recursive call
          :                    //       else (we've found a valid path):
            ++n,               //         increment n
          x                    //       \_ either way,
        ] = 1                  //       /  do r[x] = 1 to restore the current cell to 1
      )                        //     end of map() over directions
    ),                         //   end of map() over the cells of the current row
    n = 0                      //   start with n = 0
  ) | n / 4                    // end of map() over the rows; return n / 4

10

Gelée , 12 à 11 octets

ŒṪŒ!ạƝ€§ÐṂL

Essayez-le en ligne!


Explication.

ŒṪ               Positions of snake blocks.
  Œ!             All permutations.
                 For each permutation:
    ạƝ€             Calculate the absolute difference for each neighbor pair
       §            Vectorized sum.
                 Now we have a list of Manhattan distance between snake
                    blocks. Each one is at least 1.
        ÐṂL      Count the number of minimum values.
                    Because it's guaranteed that there exists a valid snake,
                    the minimum value is [1,1,1,...,1].

Les nouvelles fonctionnalités s'avèrent extrêmement utiles.
user202729

Que diriez-vous §ỊMLau lieu de §ỊP€Ssauvegarder un octet - je pense que cela devrait fonctionner?
Jonathan Allan

... ou §ÐṂLqui est un peu plus rapide.
Jonathan Allan

@JonathanAllan ne fonctionne que si le résultat est différent de zéro.
user202729

@ JonathanAllan Donc, cela finit par fonctionner.
user202729

8

Python 2 , 257 246 241 234 233 227 214 210 octets

lambda b:sum(g(b,i,j)for j,l in e(b)for i,_ in e(l))
e=enumerate
def g(b,x,y):d=len(b[0])>x>-1<y<len(b);c=eval(`b`);c[d*y][d*x]=0;return d and b[y][x]and('1'not in`c`or sum(g(c,x+a,y)+g(c,x,y+a)for a in(1,-1)))

Essayez-le en ligne!


Enregistré

  • -8 octets, merci à Kevin Cruijssen
  • -14 octets, grâce à user202729


1
La bonne langue pour le travail?
Neil

5

Python 2, 158 octets

E=enumerate
g=lambda P,x,y:sum(g(P-{o},*o)for o in P if x<0 or abs(x-o[0])+abs(y-o[1])<2)+0**len(P)
lambda L:g({(x,y)for y,r in E(L)for x,e in E(r)if e},-1,0)

Essayez-le en ligne!


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.