Tiling Batako Unik Dalam Segi Empat


13

Saya sedang menelusuri Stackoverflow dan melihat pertanyaan ini tentang memasang persegi panjang MxN, dan saya pikir itu akan bagus untuk bermain golf. Inilah tugasnya.

Dengan dimensi M dan N, tulislah sebuah program yang menampilkan berapa banyak cara unik sebuah persegi panjang MxN (N adalah jumlah baris, bukan kolom. Bukan berarti itu benar-benar penting) dapat dibuat berdasarkan batasan-batasan ini.

  1. Semua ubin berukuran 2x1 atau 3x1
  2. Semua ubin tetap dalam baris mereka (yaitu semuanya horisontal)
  3. Di antara setiap dua baris yang berdekatan, ubin tidak boleh disejajarkan, kecuali pada kedua ujungnya
  4. M dan N dijamin setidaknya 1

Misalnya, ubin yang valid dari matriks 8x3 adalah

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

Tetapi yang berikut ini tidak valid, karena baris-barisnya sejajar

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

Kasus uji:

8x3: 4

3x1: 1

1x1: 0

9x4: 10

Golf kode, jadi jawaban terpendek menang.


2
Deskripsi Anda tentang ukuran ubin tampaknya menggunakan konvensi yang berbeda dari ukuran persegi panjang. Apakah ubin sebenarnya 2x1atau 3x1? Juga apakah output untuk 4x1nol?
FryAmTheEggman

1
Selamat datang. Konsep tantangan yang bagus, namun biasanya lebih baik menggunakan kotak pasir untuk menuntaskan gagasan tantangan sebelum mempostingnya ke utama.
Beefster

@FryAmTheEggman Sepertinya OP telah mencoba membuat |s tidak berkontribusi pada panjang baris, dengan menggunakan representasi seperti ini (di mana, jika tidak ada pipa ( |), ada spasi).
Erik the Outgolfer


1
Pertanyaan yang dirujuk pada SO tidak ada lagi.
Arnauld

Jawaban:


5

Jelly , 20 byte

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

Cobalah online!


Saya tahu kecepatan bukan bagian dari spek, tetapi waktu ini bahkan 11x10 saat dijalankan pada tio. Saya tertarik pada penjelasan untuk memahami alasannya.
Nick Kennedy

@NickKennedy Itu input yang terlalu besar. Untuk lebar 11, setiap baris dapat memiliki satu dari 9 tiling yang berbeda. Untuk lebar 11 dan tinggi 10, ada 9¹⁰ = 3486784401 kemungkinan dinding, termasuk yang tidak valid. Begitulah cara kekuatan Kartesius bekerja. Jelas, TIO tidak punya waktu untuk membiarkan solusi saya menghitung seluruh susunan dinding (waktu habis setelah 60 detik). Saya akan menambahkan penjelasan ketika saya punya waktu.
Erik the Outgolfer

Terima kasih. Saya telah melihat sedikit jeli, tetapi saat ini saya bergantung pada penjelasan komentar untuk memahami apa yang dilakukan kode orang. Saya berasumsi karena masalah waktu yang memaksa kode Anda solusinya, yang merupakan cara yang masuk akal untuk meminimalkan persyaratan kode.
Nick Kennedy

Karena ketertarikan, saya telah membuat ulang di Jelly metode dalam kode R saya menggunakan bagian pertama dari kode Anda. Ada di Coba online! dan meskipun jauh lebih lama dari Anda, ia menangani jumlah yang lebih besar. Perhatikan bahwa saat ini tidak menangani 1 baris dengan benar. Saya menduga itu bisa jauh lebih ringkas, tetapi saya baru mengenal Jelly.
Nick Kennedy

4

JavaScript (ES6),  119 110 106 96  91 byte

Mengambil input sebagai (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

Cobalah online!

Berkomentar

NB: Kode ini menggunakan 3 fungsi berbeda yang saling memanggil. Ini membuatnya agak sulit untuk melacak ruang lingkup variabel. Ingat itug didefinisikan dalam ruang lingkup f dan h didefinisikan dalam ruang lingkup g.

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 byte

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

Cobalah online!

Versi dengan jeda baris:

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

Perhatikan tidak ada rekursi, dan menangani nilai m dan n yang cukup besar (mis. 24x20 -> 3.3e19)

Berikut jawaban yang dikomentari yang berfungsi kurang lebih sama dengan yang di atas, tetapi saya belum menguji semua fungsi sehingga sebenarnya dapat dibaca:

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)

Metode untuk mengambil matriks dan berulang kali mengalikannya dengan sendirinya adalah dari pertanyaan tentang stackoverflow . Pendekatan ini bekerja di sini karena secara efektif menghitung jumlah cabang kumulatif melalui barisan bata yang berbeda.

Jika paket eksternal diizinkan, saya bisa mendapatkannya ke 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

Jelly , 26 byte

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

Cobalah online!

Rusak:

Hasilkan daftar dinding yang mungkin sebagai jumlah kumulatif dengan ujungnya dihapus:

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

Temukan tabel terluar dari semua dinding yang mungkin saling berhadapan yang tidak memiliki persimpangan:

œ&L¬ɗþ`

Ambil matriks ini dengan kekuatan (N-1) dan kemudian jumlahkan semuanya:

æ*⁴’¤SS

Menggunakan bit pertama dari jawaban @ EriktheOutgolfer untuk menghasilkan daftar dinding yang mungkin, dan kemudian menggunakan persimpangan matriks dan pendekatan matriks eksponensial dari jawaban R saya. Dengan demikian, ini bekerja dengan baik bahkan dengan N. besar. Ini adalah jawaban Jelly pertama saya, dan saya kira itu bisa bermain golf lebih. Saya juga idealnya ingin mengubah bagian pertama sehingga persyaratan waktu dan memori tidak skala secara eksponensial dengan M.


0

05AB1E , 42 byte

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

Saya hampir terlalu malu untuk memposting ini, dan itu pasti bisa dipagari oleh BANYAK dengan pendekatan yang berbeda, tetapi karena butuh beberapa saat untuk menyelesaikannya saya tetap memutuskan untuk mempostingnya dan menurunkannya dari sini. Tantangannya terlihat lebih mudah daripada imo, tapi saya pasti menggunakan pendekatan yang salah di sini dan saya merasa 05AB1E bisa melakukan sekitar 25 byte ..

Cobalah online. CATATAN: Tidak hanya panjang, tetapi juga tidak efisien, karena 9x4kasus uji beroperasi dalam waktu sekitar 40 detik pada TIO ..

Penjelasan:

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

Arang , 89 byte

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

Cobalah online! Tautan adalah untuk mengucapkan versi kode. Bekerja untuk persegi panjang ukuran hingga sekitar 12 pada TIO, tetapi dapat dibuat sekitar tiga kali lebih cepat dengan biaya 2 byte dengan menggunakan sedikit memutar-mutar bukannya persimpangan daftar. Penjelasan:

Nθ

Masukkan lebar.

⊞υ⟦⟧

Mulai dengan baris tanpa batu bata.

≔⟦⟧η

Mulai tanpa baris yang selesai.

Fυ

Lingkari baris.

F⟦²¦³⟧«

Lewati batu bata.

≧⁺∧Lι§ι⁰κ

Tambahkan lebar bata ke lebar baris saat ini.

¿⁼κθ⊞ηι

Jika ini menghasilkan lebar input maka tambahkan baris ini ke daftar baris yang sudah selesai.

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

Kalau tidak, jika ini masih kurang dari lebar input maka tambahkan baris baru ke daftar baris, sehingga menyebabkannya diambil oleh iterasi kemudian.

≔Eη⟦ι⟧ζ

Buatlah daftar dinding satu baris.

F⊖N«

Lingkari satu kurang dari ketinggian.

≔ζι

Simpan daftar dinding.

≔⟦⟧ζ

Kosongkan daftar dinding.

Fι

Ulangi daftar dinding yang disimpan.

Fη

Lingkari baris yang sudah selesai.

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

Jika baris dapat ditambahkan ke dinding ini maka tambahkan itu ke daftar dinding.

ILζ

Keluarkan panjang daftar dinding terakhir.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.