Dove sta andando quel serpente?


35

Scrivi una funzione (utilizzando il minor numero di byte possibile) che accetta una matrice bidimensionale di qualsiasi numero di colonne e righe in cui:

  • 0 rappresenta un blocco vuoto,
  • 1 rappresenta il blocco di serpenti.

La funzione deve restituire il numero di possibili percorsi percorsi dal serpente.

Esempio 1:

Ingresso:

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

Produzione: 2

Nell'esempio sopra, la funzione tornerà 2perché la risposta è una delle seguenti:

enter image description here

Esempio 2:

Ingresso:

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

Produzione: 6

In questo esempio la funzione tornerà 6perché la risposta è una delle seguenti:

enter image description here

Nota:

Quando si valuta l'input, si può presumere che:

  • Le matrici che rappresentano le colonne avranno sempre le stesse dimensioni (quindi le matrici sono rettangolari);
  • Esiste almeno 1 percorso valido;
  • Il serpente non può camminare attraverso i bordi (come può accadere in alcune versioni di serpente);
  • Il serpente avrà sempre almeno 2 blocchi;
  • Il serpente non può muoversi in diagonale;
  • I percorsi sono diretti. (quindi, due percorsi che terminano in posizioni diverse ma che sembrano esattamente uguali non sono lo stesso percorso, si sommeranno al totale)

13
Benvenuti in PPCG! Bella prima sfida.
Laikoni,

5
Nota minore: "Ci saranno sempre almeno una riga e una colonna" è ridondante, dato che il serpente avrà sempre almeno 2 blocchi.
Stewie Griffin,

2
Casi di prova suggeriti: quello fornito da @StewieGriffin e [[0,0,1,1],[0,0,1,1],[0,0,1,1]]. La maggior parte delle risposte danno 16, ma una dà 15.
Kevin Cruijssen,

2
Sembra che tutti finora (incluso me) abbiano ipotizzato che 2 percorsi che terminano in posizioni diverse ma che guardano esattamente lo stesso non siano lo stesso percorso. Penso che questo debba essere esplicitamente specificato.
Arnauld,

2
@Arnauld - esatto. Due percorsi che terminano in posizioni diverse ma che sembrano esattamente uguali non sono lo stesso percorso , si sommeranno al totale. Nel tuo esempio il totale dovrebbe essere 16 se non sbaglio - non posso calcolare con precisione in questo momento ma ottieni il punto
Adelin

Risposte:


11

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

Dichiarazione di importazione della libreria (16 byte):

<<Combinatorica`

Corpo della funzione effettiva (83 byte):

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

Provalo online!


Si noti che la domanda richiede solo il numero del percorso hamiltoniano nel grafico.

Tuttavia, (per qualche motivo) la HamiltonianPathfunzione non funziona davvero con il grafico diretto ( esempio ). Quindi, ho usato la soluzione descritta in questa domanda Mathematica.SE :

  • Aggiungi un vertice (chiamato True) collegato a tutti gli altri vertici.
  • Conta il numero del ciclo hamiltoniano sul grafico risultante.

Il grafico è costruito usando MakeGraph(fastidiosamente non ci sono built-in direttamente equivalenti), usando la funzione booleana ##||Norm[#-#2]==1&, che restituisce Truese e solo se uno degli argomenti è Trueo la distanza tra i due vertici è 1.


Tr[1^x]non può essere utilizzato al posto di Length@xe <2non può essere utilizzato al posto di ==1.


HamiltonianPathpuò essere utilizzato se il grafico non viene reindirizzato, con il corpo della funzione occupa 84 byte (esattamente 1 byte in più rispetto all'invio corrente):

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

Provalo online!


10

JavaScript (ES6), 154 134 byte

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

Provalo online!

Come?

Metodo

Partendo da ogni possibile cella, riempiamo la matrice inondando, eliminando tutte le celle sulla nostra strada. Ogni volta che la matrice non contiene più 1 , incrementiamo il numero n di possibili percorsi.

Ogni percorso valido viene contato 4 volte a causa della direzione scelta sull'ultima cella, che in realtà non ha importanza. Pertanto, il risultato finale è n / 4 .

Funzione ricorsiva

Invece di chiamare la funzione ricorsiva g () dal callback della seconda mappa () in questo modo ...

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

... definiamo la funzione ricorsiva g () direttamente come il callback di map () :

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

Nonostante la formula piuttosto lunga, y=1/y?y:Ynecessaria per impostare il valore iniziale di y , ciò consente di risparmiare 2 byte complessivi.

Codice commentato

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

Gelatina , 12 11 byte

ŒṪŒ!ạƝ€§ÐṂL

Provalo online!


Spiegazione.

ŒṪ               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].

Le nuove funzionalità si dimostrano estremamente utili.
user202729,

Che ne dici §ỊMLinvece di §ỊP€Ssalvare un byte - penso che dovrebbe funzionare?
Jonathan Allan,

... o §ÐṂLche è un po 'più veloce.
Jonathan Allan,

@JonathanAllan Funziona solo se il risultato è diverso da zero.
user202729

@JonathanAllan Quindi alla fine funziona davvero.
user202729

8

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

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

Provalo online!


Salvato

  • -8 byte, grazie a Kevin Cruijssen
  • -14 byte, grazie all'utente202729


1
La lingua giusta per il lavoro?
Neil,

5

Python 2, 158 byte

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)

Provalo online!


3

Haskell , 187 155 byte

r=filter
l=length
(a,b)?(x,y)=abs(a-x)+abs(b-y)==1
l#x=sum[p!r(/=p)l|p<-x]
p![]=1
p!l=l#r(p?)l
f x|l<-[(i,j)|i<-[0..l x-1],j<-[0..l(x!!0)-1],x!!i!!j>0]=l#l

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.