Unikalne płytki ceglane w prostokącie

13

Przeglądałem Stackoverflow i zobaczyłem to pytanie o kafelkowanie prostokąta MxN i pomyślałem, że będzie to świetne miejsce do gry w golfa. Oto zadanie.

Biorąc pod uwagę wymiary M i N, napisz program, który wyświetli, ile unikalnych sposobów można prostokątować prostokątem MxN (N to liczba wierszy, a nie kolumn. To nie ma znaczenia), biorąc pod uwagę te ograniczenia.

  1. Wszystkie płytki to 2x1 lub 3x1
  2. Wszystkie płytki pozostają w swoim rzędzie (tzn. Wszystkie są poziome)
  3. Pomiędzy każdym dwoma sąsiadującymi rzędami płytki nie powinny być wyrównane, z wyjątkiem dwóch końców
  4. Gwarantowane jest, że M i N wynoszą co najmniej 1

Na przykład poprawne kafelkowanie macierzy 8x3 to

  2    3     3
  |    |     |
  v    v     v
 _______________
|___|_____|_____| 
|_____|_____|___|
|___|_____|_____|

Ale następujące elementy byłyby nieprawidłowe, ponieważ wiersze są wyrównane

  2    3     3
  |    |     |
  v    v     v
 _______________
|___|_____|_____| 
|_____|___|_____|
|_____|_____|___|

Przypadki testowe:

8x3: 4

3x1: 1

1x1: 0

9x4: 10

Code golf, więc najkrótsza odpowiedź wygrywa.

rtpax
źródło
2
Twój opis wielkości płytek wydaje się używać innej konwencji niż rozmiar prostokąta. Czy płytki są rzeczywiście 2x1czy 3x1? Czy jest również wyjście dla 4x1zera?
FryAmTheEggman
1
Witamy. Fajna koncepcja wyzwania, jednak zwykle najlepiej jest użyć piaskownicy, aby opracować pomysły na wyzwania, zanim opublikujesz je na main.
Beefster
@FryAmTheEggman Wygląda OP próbowali |a nie przyczyniają się do długości rzędu stosując reprezentację jak to (w których, o ile nie jest to rura ( |), to jest przestrzeń).
Erik the Outgolfer
Powiązane: Zbuduj stabilny mur z cegły
xnor
1
Odpowiedzi na pytanie dotyczące SO już nie ma.
Arnauld

Odpowiedzi:

5

Galaretka , 20 bajtów

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸ṗfƝẸ$€ċ0

Wypróbuj online!

Erik the Outgolfer
źródło
Wiem, że prędkość nie była częścią specyfikacji, ale upłynęło to nawet 11x10, gdy uruchomiono na tio. Byłbym zainteresowany wyjaśnieniem, aby zrozumieć, dlaczego.
Nick Kennedy
@NickKennedy To zbyt duży wkład. Dla szerokości 11 każdy rząd może mieć jeden z 9 różnych nachyleń. Dla szerokości 11 i wysokości 10 istnieje 9¹⁰ = 3486784401 możliwe ściany, w tym nieprawidłowe. Tak działa siła kartezjańska. Oczywiście, TIO nie ma czasu, aby moje rozwiązanie obliczyło całą ścianę (upływa limit czasu po 60 sekundach). Dodam wyjaśnienie, kiedy będę miał czas.
Erik the Outgolfer
dzięki. Patrzyłem trochę na galaretkę, ale w tej chwili polegam na komentowanych wyjaśnieniach, aby zrozumieć, co robi ludzki kod. Założyłem, biorąc pod uwagę problem z czasem, że brutalny kod wymusza rozwiązanie, co jest rozsądnym sposobem na zminimalizowanie wymagań dotyczących kodu.
Nick Kennedy
W interesie odtworzyłem w Galarecie metodę w moim kodzie R, używając pierwszej części twojego kodu. Jest na Wypróbuj online! i chociaż jest znacznie dłuższy niż twój, obsługuje większe liczby. Zauważ, że obecnie nie obsługuje poprawnie 1 rzędu. Podejrzewam, że mogłoby być o wiele bardziej zwięzłe, ale jestem nowy w Jelly.
Nick Kennedy
4

JavaScript (ES6),  119 110 106 96  91 bajtów

(N,M)

f=(n,m,p=0,g=(w,h=x=>g(p[g[w-=x]=1,w]||w)*g[w]--)=>w>3?h(2)+h(1):w>1&&f(n,m-1,g))=>m?g(n):1

Wypróbuj online!

Skomentował

gfhg

f = (                    // f is a recursive function taking:
  n,                     //   n = number of columns
  m,                     //   m = number of rows
  p = 0,                 //   p = object holding the previous row
  g = (                  //   g = recursive function taking:
    w,                   //     w = remaining width that needs to be filled in the
                         //         current row
    h = x =>             //     h = helper function taking x
                         // h body:
      g(                 //   recursive call to g:
        p[g[w -= x] = 1, //     subtract either 2 or 1 from w and mark this width as used
          w              //     test p[w]
        ]                //     pass p[w] if p[w] = 1 (which will force the next iteration
                         //     to fail immediately)
        || w             //     otherwise, pass w
      )                  //   end of recursive call
      * g[w]--           //   then restore g[w] to 0
  ) =>                   // g body:
    w > 3 ?              //   if w > 3, we need to insert at least 2 more bricks:
      h(2) + h(1)        //     invoke h with x = 2 and x = 1
    :                    //   else:
      w > 1              //     this is the last brick; we just check if it can be inserted
      &&                 //     abort if w is equal to 1 (a brick does not fit in there)
      f(                 //     otherwise, do a recursive call to f:
        n,               //       n is unchanged
        m - 1,           //       decrement m
        g                //       pass g as the new reference row
      )                  //     end of recursive call
) =>                     // f body:
  m ? g(n) : 1           //   yield 1 if we made it to the last row or call g otherwise
Arnauld
źródło
1

R , 243 231 bajtów

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=Map)`if`(m<2,0,sum((e=eigen(lengths(outer(p<-unlist(M(M,list(function(x,y)cumsum(2+1:y%in%x)),M(combn,j,i,s=F),j),F),p,Vectorize(intersect)))<2))$ve%*%diag(e$va^(n-1))%*%solve(e$ve)))

Wypróbuj online!

Wersja z podziałami linii:

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=Map)`if`(m<2,0,
sum((e=eigen(lengths(outer(p<-unlist(M(M,list(function(x,y)cumsum(2+1:y%in%x)),
M(combn,j,i,s=F),j),F),p,Vectorize(intersect)))<2))$ve%*%diag(e$va^(n-1))%*%solve(e$ve)))

Nie zauważaj rekurencji i obsługuje dość duże wartości min (np. 24x20 -> 3,3e19)

Oto skomentowana odpowiedź, która działa mniej więcej tak samo jak powyżej, ale usunąłem wszystkie funkcje, więc jest w rzeczywistości czytelna:

f <- function(m,n) {
  # First work out what potential combinations of 2s and 3s add up to m
  i <- 2*0:(m %/% 6) + m %% 2 # Vector with numbers of possible 3s
  j <- i + (m - 3 * i) / 2 # Vector with total number of 2s and 3s
  if (m < 2) {
    0 # If wall less than 2 wide, no point in continuing because answer is 0
  } else {
    # Work out all possible positions of threes for each set
    positions_of_threes <- Map(combn, j, i, simplify = FALSE)
    # Function to work out the cumulative distance along the wall for a given
    # Set of three positions and number of bricks
    make_cumulative_bricks <- function(pos_threes, n_bricks) {
      bricks <- 1:n_bricks %in% pos_threes
      cumsum(2 + bricks)
    }
    # Find all possible rows with cumulative width of wall
    # Note because this is a `Map` with depth two that needs to be vectorised
    # for both `positions_of_threes` and `j`, and we're using base R, the
    # function `make_cumulative_bricks` needs to be placed in a list
    cum_bricks <- Map(Map, list(make_cumulative_bricks), positions_of_threes, j)
    # Finally we have the list of possible rows of bricks as a flat list
    cum_bricks_unlisted <- unlist(cum_bricks, recursive = FALSE)
    # Vectorise the intersect function
    intersect_v <- Vectorize(intersect, SIMPLIFY = FALSE)
    # Find the length of all possible intersects between rows
    intersections <- outer(cum_bricks_unlisted, cum_bricks_unlisted, intersect_v)
    n_intersections <- lengths(intersections)
    # The ones not lined up will only have a single intersect at `m`
    not_lined_up <- n_intersections == 1
    # Now use method described at /programming//a/9459540/4998761
    # to calculate the (matrix of TRUE/FALSE for lined-up) to the power of `n`
    eigen_nlu <- eigen(not_lined_up)
    final_mat <- eigen_nlu$vectors %*%
      diag(eigen_nlu$values ^ (n - 1)) %*%
      solve(eigen_nlu$vectors)
    # The sum of this matrix is what we're looking for
    sum(final_mat)
  }
}
f(20,20)

Metoda pobierania macierzy i jej wielokrotnego mnożenia pochodzi z pytania o przepełnienie stosu . To podejście działa tutaj, ponieważ skutecznie oblicza łączną liczbę gałęzi w różnych możliwych rzędach cegieł.

Jeśli dozwolone są pakiety zewnętrzne, mogę sprowadzić je do 192:

function(m,n,i=2*0:(m%/%6)+m%%2,j=i+(m-3*i)/2,M=purrr::map2)`if`(m<2,0,sum(expm::`%^%`(lengths(outer(p<-unlist(M(M(j,i,combn,s=F),j,M,~cumsum(2+1:.y%in%.)),F),p,Vectorize(intersect)))<2,n-1)))
Nick Kennedy
źródło
1

Galaretka , 26 bajtów

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸œ&L¬ɗþ`æ*⁴’¤SS

Wypróbuj online!

Zepsuty:

Wygeneruj listę możliwych ścian jako sumy zbiorcze z usuniętym końcem:

2*ḃ€2‘ÄṪ⁼¥Ƈ⁸

Znajdź zewnętrzny stół wszystkich możliwych ścian, które nie mają żadnych skrzyżowań:

œ&L¬ɗþ`

Weź tę macierz do potęgi (N-1), a następnie podsumuj wszystko:

æ*⁴’¤SS

Używa pierwszego bitu z odpowiedzi @ EriktheOutgolfer, aby wygenerować listę możliwych ścian, a następnie stosuje podejście przecięcia macierzy i wykładnika macierzy z mojej odpowiedzi R. Jako taki, działa dobrze nawet z dużymi N. To jest moja pierwsza odpowiedź na żelki i podejrzewam, że można więcej grać w golfa. Idealnie chciałbym również zmienić pierwszą sekcję, aby wymagania dotyczące czasu i pamięci nie skalowały się wykładniczo z M.

Nick Kennedy
źródło
0

05AB1E , 42 bajty

Åœʒ23yåP}€œ€`Ùε.¥¦¨}IиI.ÆÙεøyíø‚€€üQOO_P}O

Jestem prawie zbyt zawstydzony, aby to opublikować, i zdecydowanie może grać w golfa przez LOT z innym podejściem, ale ponieważ zajęło to trochę czasu, postanowiłem opublikować to i odtąd grać w golfa. Wyzwanie wygląda na łatwiejsze niż jest na Imo, ale zdecydowanie używam tutaj niewłaściwego podejścia i mam wrażenie, że 05AB1E może zrobić około 25 bajtów ..

Wypróbuj online. UWAGA: Jest nie tylko długi, ale także nieefektywny, ponieważ 9x4przypadek testowy działa na TIO w około 40 sekund.

Wyjaśnienie:

Ŝ             # Get all possible ways to sum to the (first) implicit input
               #  i.e. 8 → [[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,2],[1,1,1,1,1,3],[1,1,1,1,2,2],[1,1,1,1,4],[1,1,1,2,3],[1,1,1,5],[1,1,2,2,2],[1,1,2,4],[1,1,3,3],[1,1,6],[1,2,2,3],[1,2,5],[1,3,4],[1,7],[2,2,2,2],[2,2,4],[2,3,3],[2,6],[3,5],[4,4],[8]]
  ʒ23yåP}      # Only leave those consisting of 2s and/or 3s
               #  → [[2,2,2,2],[2,3,3]]
         €œ    # For each: get all permutations
           €`  # Flatten this list of lists once
             Ù # And uniquify it (leaving all possible distinct rows of bricks)
               #  → [[2,2,2,2],[3,3,2],[3,2,3],[2,3,3]]
ε    }         # For each:
             #  Get the cumulative sum
   ¦¨          #  With the leading 0 and trailing first input removed
               #   → [[2,4,6],[3,6],[3,5],[2,5]]
      Iи       # Repeat this list the second input amount of times
               #  i.e. 3 → [[2,4,6],[3,6],[3,5],[2,5],[2,4,6],[3,6],[3,5],[2,5],[2,4,6],[3,6],[3,5],[2,5]]
        I    # Get all combinations of lists the size of the second input
           Ù   # And uniquify the result (leaving all possible distinct walls)
               #  → [[[2,4,6],[3,6],[3,5]],[[2,4,6],[3,6],[2,5]],[[2,4,6],[3,6],[2,4,6]],[[2,4,6],[3,6],[3,6]],[[2,4,6],[3,5],[2,5]],[[2,4,6],[3,5],[2,4,6]],[[2,4,6],[3,5],[3,6]],[[2,4,6],[3,5],[3,5]],[[2,4,6],[2,5],[2,4,6]],[[2,4,6],[2,5],[3,6]],[[2,4,6],[2,5],[3,5]],[[2,4,6],[2,5],[2,5]],[[2,4,6],[2,4,6],[3,6]],[[2,4,6],[2,4,6],[3,5]],[[2,4,6],[2,4,6],[2,5]],[[2,4,6],[2,4,6],[2,4,6]],[[3,6],[3,5],[2,5]],[[3,6],[3,5],[2,4,6]],[[3,6],[3,5],[3,6]],[[3,6],[3,5],[3,5]],[[3,6],[2,5],[2,4,6]],[[3,6],[2,5],[3,6]],[[3,6],[2,5],[3,5]],[[3,6],[2,5],[2,5]],[[3,6],[2,4,6],[3,6]],[[3,6],[2,4,6],[3,5]],[[3,6],[2,4,6],[2,5]],[[3,6],[2,4,6],[2,4,6]],[[3,6],[3,6],[3,5]],[[3,6],[3,6],[2,5]],[[3,6],[3,6],[2,4,6]],[[3,6],[3,6],[3,6]],[[3,5],[2,5],[2,4,6]],[[3,5],[2,5],[3,6]],[[3,5],[2,5],[3,5]],[[3,5],[2,5],[2,5]],[[3,5],[2,4,6],[3,6]],[[3,5],[2,4,6],[3,5]],[[3,5],[2,4,6],[2,5]],[[3,5],[2,4,6],[2,4,6]],[[3,5],[3,6],[3,5]],[[3,5],[3,6],[2,5]],[[3,5],[3,6],[2,4,6]],[[3,5],[3,6],[3,6]],[[3,5],[3,5],[2,5]],[[3,5],[3,5],[2,4,6]],[[3,5],[3,5],[3,6]],[[3,5],[3,5],[3,5]],[[2,5],[2,4,6],[3,6]],[[2,5],[2,4,6],[3,5]],[[2,5],[2,4,6],[2,5]],[[2,5],[2,4,6],[2,4,6]],[[2,5],[3,6],[3,5]],[[2,5],[3,6],[2,5]],[[2,5],[3,6],[2,4,6]],[[2,5],[3,6],[3,6]],[[2,5],[3,5],[2,5]],[[2,5],[3,5],[2,4,6]],[[2,5],[3,5],[3,6]],[[2,5],[3,5],[3,5]],[[2,5],[2,5],[2,4,6]],[[2,5],[2,5],[3,6]],[[2,5],[2,5],[3,5]],[[2,5],[2,5],[2,5]]]
ε              # Map all walls `y` to:
 ø             #  Zip/transpose; swapping rows and columns
 yí            #  Reverse each row in a wall `y`
   ø           #  Also zip/transpose those; swapping rows and columns
              #  Pair both
              #  For both:
              #   For each column:
    ü          #    For each pair of bricks in a column:
     Q         #     Check if they are equal to each other (1 if truthy; 0 if falsey)
    O          #    Then take the sum of these checked pairs for each column
   O           #   Take the sum of that entire column
   _           #   Then check which sums are exactly 0 (1 if 0; 0 if anything else)
   P           #   And check for which walls this is only truthy by taking the product
}O             # After the map: sum the resulting list
               # (and output it implicitly as result)
Kevin Cruijssen
źródło
0

Węgiel drzewny , 89 bajtów

Nθ⊞υ⟦⟧≔⟦⟧ηFυF⟦²¦³⟧«≧⁺∧Lι§ι⁰κ¿⁼κθ⊞ηι¿‹κθ⊞υ⁺⟦κ⟧ι»≔Eη⟦ι⟧ζF⊖N«≔ζι≔⟦⟧ζFιFη¿¬⊙§κ⁰№λμ⊞ζ⁺⟦λ⟧κ»ILζ

Wypróbuj online! Link jest do pełnej wersji kodu. Działa w przypadku prostokątów o wielkości do około 12 w TIO, ale można je wykonać około trzy razy szybciej, kosztem 2 bajtów, stosując kręcenie bitów zamiast przecinania listy. Wyjaśnienie:

Nθ

Wprowadź szerokość.

⊞υ⟦⟧

Zacznij od rzędu bez cegieł.

≔⟦⟧η

Zacznij bez zakończonych wierszy.

Fυ

Pętla nad rzędami.

F⟦²¦³⟧«

Pętla nad cegłami.

≧⁺∧Lι§ι⁰κ

Dodaj szerokość cegły do ​​bieżącej szerokości wiersza.

¿⁼κθ⊞ηι

Jeśli spowoduje to szerokość wejściową, dodaj ten wiersz do listy zakończonych wierszy.

¿‹κθ⊞υ⁺⟦κ⟧ι»

W przeciwnym razie, jeśli jest to nadal mniej niż szerokość wejściowa, dodaj nowy wiersz do listy wierszy, powodując, że zostanie on przechwycony przez późniejszą iterację.

≔Eη⟦ι⟧ζ

Zrób listę ścian jednego rzędu.

F⊖N«

Zapętlić o jeden mniej niż wysokość.

≔ζι

Zapisz listę ścian.

≔⟦⟧ζ

Wyczyść listę ścian.

Fι

Pętla nad zapisaną listą ścian.

Fη

Pętlę nad ukończonymi rzędami.

¿¬⊙§κ⁰№λμ⊞ζ⁺⟦λ⟧κ»

Jeśli wiersz można dodać do tej ściany, dodaj go do listy ścian.

ILζ

Podaj długość końcowej listy ścian.

Neil
źródło