Dokąd zmierza ten wąż?

35

Napisz funkcję (wykorzystującą jak najmniej bajtów), która pobiera dwuwymiarową tablicę dowolnej liczby kolumn i wierszy, w której:

  • 0 reprezentuje pusty blok,
  • 1 reprezentuje blok węża.

Funkcja musi zwracać liczbę możliwych ścieżek, które przebył wąż.

Przykład 1:

Wkład:

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

Wydajność: 2

W powyższym przykładzie funkcja zwróci, 2ponieważ odpowiedź jest jedna z:

wprowadź opis zdjęcia tutaj

Przykład 2:

Wkład:

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

Wydajność: 6

W tym przykładzie funkcja zwróci, 6ponieważ odpowiedź jest jedna z:

wprowadź opis zdjęcia tutaj

Uwaga:

Oceniając dane wejściowe, możesz założyć, że:

  • Tablice reprezentujące kolumny zawsze będą miały takie same rozmiary (więc tablice są prostokątne);
  • Istnieje co najmniej 1 poprawna ścieżka;
  • Wąż nie może przejść przez krawędzie (co może się zdarzyć w niektórych wersjach węża);
  • Wąż zawsze będzie miał co najmniej 2 bloki;
  • Wąż nie może poruszać się po przekątnej;
  • Ścieżki są skierowane. (więc dwie ścieżki kończące się w różnych pozycjach, ale poza tym wyglądające dokładnie tak samo, nie są tą samą ścieżką, sumują się do całości)
Adelina
źródło
13
Witamy w PPCG! Ładne pierwsze wyzwanie.
Laikoni
5
Drobna uwaga: „Zawsze będzie co najmniej jeden wiersz i jedna kolumna” jest zbędny, biorąc pod uwagę, że wąż zawsze będzie miał co najmniej 2 bloki.
Stewie Griffin,
2
Sugerowane przypadki testowe: ten podany przez @StewieGriffin i [[0,0,1,1],[0,0,1,1],[0,0,1,1]]. Większość odpowiedzi daje 16, ale jedna daje 15.
Kevin Cruijssen
2
Wygląda na to, że wszyscy (łącznie ze mną) przyjęli założenie, że 2 ścieżki kończące się w różnych pozycjach, ale poza tym wyglądające dokładnie tak samo, nie są tą samą ścieżką. Myślę, że należy to wyraźnie określić.
Arnauld
2
@Arnauld - zgadza się. Dwie ścieżki kończące się na różnych pozycjach, ale poza tym wyglądające dokładnie tak samo, nie są tą samą ścieżką , to zsumuje się. W twoim przykładzie suma powinna wynosić 16, jeśli się nie mylę - nie mogę teraz dokładnie obliczyć, ale masz rację
Adelin

Odpowiedzi:

11

Wolfram Language (Mathematica) , 16 + 83 = 99 bajtów

Instrukcja importu biblioteki (16 bajtów):

<<Combinatorica`

Rzeczywista treść funkcji (83 bajty):

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

Wypróbuj online!


Zauważ, że w pytaniu pytaj tylko o liczbę ścieżek hamiltonowskich na wykresie.

Jednak (z jakiegoś powodu) HamiltonianPathfunkcja tak naprawdę nie działa z ukierunkowanym wykresem ( przykład ). Użyłem więc obejścia opisanego w tym pytaniu Mathematica.SE :

  • Dodaj wierzchołek (nazywany True), który jest połączony ze wszystkimi innymi wierzchołkami.
  • Policz liczbę cykli Hamiltona na wynikowym wykresie.

Wykres jest konstruowany przy użyciu MakeGraph(irytujące, że nie ma bezpośrednio równoważnego wbudowanego), przy użyciu funkcji boolean ##||Norm[#-#2]==1&, która zwraca, Truejeśli tylko jeden z argumentów jest Truelub odległość między dwoma wierzchołkami jest 1.


Tr[1^x]nie można użyć zamiast Length@xi <2nie można użyć zamiast ==1.


HamiltonianPathmożna użyć, jeśli wykres nie jest przekierowany, a ciało funkcji zajmuje 84 bajty (dokładnie 1 bajt więcej niż bieżące przesłanie):

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

Wypróbuj online!

użytkownik202729
źródło
10

JavaScript (ES6), 154 134 bajtów

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

Wypróbuj online!

W jaki sposób?

metoda

Zaczynając od każdej możliwej komórki, wypełniamy matrycę, usuwając wszystkie komórki po drodze. Ilekroć macierz nie zawiera więcej 1 , zwiększamy liczbę n możliwych ścieżek.

Każda ważna ścieżka jest liczona 4 razy ze względu na kierunek wybrany w ostatniej komórce, co w rzeczywistości nie ma znaczenia. Dlatego końcowy wynik to n / 4 .

Funkcja rekurencyjna

Zamiast wywoływać funkcję rekurencyjną g () z wywołania zwrotnego drugiej mapy () w ten sposób ...

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

... możemy zdefiniować rekurencyjnej funkcji g () bezpośrednio jako zwrotnego z mapy () :

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

Pomimo dość długiej formuły y=1/y?y:Ywymaganej do ustawienia początkowej wartości y , pozwala to zaoszczędzić 2 bajty ogółem.

Skomentowany kod

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
Arnauld
źródło
10

Galaretka , 12 11 bajtów

ŒṪŒ!ạƝ€§ÐṂL

Wypróbuj online!


Wyjaśnienie.

ŒṪ               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].
użytkownik202729
źródło
Nowe funkcje okazują się niezwykle przydatne.
user202729,
A może §ỊMLzamiast §ỊP€Szapisać bajt - myślę, że powinien działać?
Jonathan Allan
... lub §ÐṂLktóry jest trochę szybszy.
Jonathan Allan
@JonathanAllan Działa tylko wtedy, gdy wynik jest niezerowy.
user202729
@JonathanAllan Więc tak naprawdę to działa.
user202729
8

Python 2 , 257 246 241 234 233 227 214 210 bajtów

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

Wypróbuj online!


Zapisano

  • -8 bajtów, dzięki Kevin Cruijssen
  • -14 bajtów, dzięki user202729
TFeld
źródło
1
Właściwy język do pracy?
Neil
5

Python 2, 158 bajtów

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)

Wypróbuj online!

KSab
źródło
3

Haskell , 187 155 bajtów

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

Wypróbuj online!

użytkownik 28667
źródło