Унікальні цегляні облицювання в прямокутнику


14

Я переглядав Stackoverflow і бачив це питання щодо плитки прямокутника MxN, і думав, що це буде чудово для гольфу. Ось завдання.

Враховуючи розмірність M і N, напишіть програму, яка виводить, скільки унікальних способів прямокутник MxN (N - кількість рядків, а не стовпців. Неважливо, що це насправді має значення) може бути викладений плиткою з урахуванням цих обмежень.

  1. Усі плитки 2х1 або 3х1
  2. Усі плитки залишаються в ряді (тобто всі вони горизонтальні)
  3. Між кожні два сусідні ряди плитки не повинні вирівнюватися, за винятком двох кінців
  4. M і N гарантовано становлять щонайменше 1

Наприклад, допустимою буде плитка матриці 8x3

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

Але наступне було б недійсним, оскільки рядки вирівнюються

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

Тестові приклади:

8х3: 4

3х1: 1

1x1: 0

9х4: 10

Код гольфу, тому найкоротша відповідь виграє.


2
У вашому описі розміру плитки, схоже, використовується інша умова від розміру прямокутника. Насправді плитка 2x1чи 3x1? Також є вихід за 4x1нуль?
FryAmTheEggman

1
Ласкаво просимо. Приємна концепція виклику, проте зазвичай найкраще використовувати пісочницю, щоб вибити ідеї викликів, перш ніж розміщувати їх на головній.
Beefster

@FryAmTheEggman Схоже OP спробував зробити |їй не сприяти довжині рядка, використовуючи уявлення , як це (де, якщо не трубка ( |), є прогалина).
Ерік Аутгольфер


1
Посилане питання на SO більше не є.
Арнольд

Відповіді:


5

Желе , 20 байт

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

Спробуйте в Інтернеті!


Я знаю, що швидкість не була частиною специфікацій, але ця рівномірність вийшла навіть на 11x10 під час бігу на tio. Мені було б цікаво пояснення, щоб зрозуміти, чому.
Нік Кеннеді

@NickKennedy Це занадто великий внесок. Для ширини 11 кожен ряд може мати один з 9 різних облицювань. Для ширини 11 та висоти 10 передбачено 9¹⁰ = 3486784401 можливих стін, у тому числі недійсних. Ось так працює декартова сила. Очевидно, що у TIO немає часу, щоб моє рішення дозволило обчислити весь масив стін (він закінчується через 60 секунд). Я додам пояснення, коли знайду час.
Ерік Атголфер

Спасибі. Я трохи подивився на желе, але на даний момент я покладаюся на коментовані пояснення, щоб зрозуміти, що робить код людей. Я вважаю, що враховуючи час, що ваш код грубої сили змушує рішення, що є розумним способом мінімізації вимог до коду.
Нік Кеннеді

З інтересу я відтворив у Jelly метод у своєму R-коді, використовуючи першу частину вашого коду. Це у Спробуйте онлайн! і хоча він значно довший, ніж ваш, він обробляє більші числа. Зверніть увагу, що на даний момент він не обробляє належним чином один ряд Я підозрюю, що це може бути набагато більш лаконічним, але я новачок у Jelly.
Нік Кеннеді

4

JavaScript (ES6),  119 110 106 96  91 байт

Приймає вхід як .(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

Спробуйте в Інтернеті!

Прокоментував

Примітка: Цей код використовує 3 різні функції, які дзвонять один одному. Це ускладнює відстеження обсягу змінних. Майте на увазі, що визначено в межах а визначено в межах .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

1

R , 243 231 байт

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

Спробуйте в Інтернеті!

Версія з розривами рядків:

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

Зауважте, що немає рекурсії, і обробляє досить великі значення m і n (наприклад, 24x20 -> 3.3e19)

Ось коментована відповідь, яка працює в більшій мірі так само, як описано вище, але я зняв усі функції, щоб її можна було прочитати:

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)

Метод взяття матриці та багаторазового її множення походить із запитання про stackoverflow . Цей підхід працює тут, оскільки він ефективно обчислює сукупну кількість гілок через різні можливі ряди цегли.

Якщо дозволені зовнішні пакети, я можу знизити його до 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)))

1

Желе , 26 байт

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

Спробуйте в Інтернеті!

Зломаний:

Створіть список можливих стін як сукупних сум із вилученим кінцем:

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

Знайдіть зовнішню таблицю всіх можливих стін одна проти одної, що не мають перетинів:

œ&L¬ɗþ`

Візьміть цю матрицю до потужності (N-1) і потім підсумуйте її:

æ*⁴’¤SS

Використовує перший біт з відповіді @ EriktheOutgolfer для генерування списку можливих стін, а потім використовує матричний перетин та підхід до експозиції матриці з моєї відповіді R. Як такий, він добре працює навіть з великим N. Це моя перша відповідь на Jelly, і я підозрюю, що в ньому можна більше пограти в гольф. Я також хотів би змінити перший розділ, щоб вимоги до часу та пам’яті не змінювались експоненціально з М.


0

05AB1E , 42 байти

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

Мені майже занадто соромно публікувати це, і це, безумовно, може бути гольф ЛОТОМ з іншим підходом, але оскільки на це знадобився певний час, я все-таки вирішив опублікувати його і все-таки гольф. Виклик виглядає легше, ніж це іммо, але я, безумовно, тут використовую неправильний підхід, і я маю відчуття, що 05AB1E міг би робити близько 25 байт ..

Спробуйте в Інтернеті. ПРИМІТКА: Мало того, що він довгий, він ще й неефективний, оскільки 9x4тестовий випадок працює близько 40 секунд на TIO.

Пояснення:

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

0

Вугілля деревне , 89 байт

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

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Працює для прямокутників розміром до приблизно 12 в TIO, але їх можна зробити приблизно втричі швидшими за 2 байти, використовуючи подвійне подвійне замість перетину списку. Пояснення:

Nθ

Введіть ширину.

⊞υ⟦⟧

Почніть з ряду без цеглинок.

≔⟦⟧η

Почніть без завершених рядків.

Fυ

Петля над рядами.

F⟦²¦³⟧«

Петля над цеглою.

≧⁺∧Lι§ι⁰κ

Додайте ширину цегли до поточної ширини рядка.

¿⁼κθ⊞ηι

Якщо це призведе до ширини введення, додайте цей рядок до списку завершених рядків.

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

В іншому випадку, якщо це все-таки менше вхідної ширини, тоді додайте новий рядок до списку рядків, тим самим спричиняючи його вибору пізнішою ітерацією.

≔Eη⟦ι⟧ζ

Складіть список стін одного ряду.

F⊖N«

Петля на одну менше, ніж висота.

≔ζι

Збережіть список стін.

≔⟦⟧ζ

Очистити список стін.

Fι

Проведіть петлю над збереженим списком стін.

Fη

Проведіть петлю над завершеними рядами.

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

Якщо рядок можна додати до цієї стіни, тоді додайте його до списку стін.

ILζ

Виведіть довжину остаточного списку стін.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.