矩形内的独特砖瓦


13

我在浏览#1,看到这个问题有关平铺显示M×N的矩形,我认为这将是伟大的高尔夫球场。这是任务。

给定尺寸M和N,编写一个程序,输出在给定这些约束的情况下可以平铺MxN矩形(N是行数,而不是列数。这并不重要)有多少种独特方式。

  1. 所有图块均为2x1或3x1
  2. 所有图块都留在其行内(即它们都是水平的)
  3. 每两个相邻的行之间,除了两端之外,磁贴不应对齐
  4. M和N保证至少为1

例如,有效的8x3矩阵切片将是

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

但是以下内容将无效,因为行对齐

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

测试用例:

8x3:4

3x1:1

1x1:0

9x4:10

编码高尔夫,最短的答案将获胜。


2
您对图块大小的描述似乎使用了与矩形大小不同的约定。瓷砖是真的2x1还是3x1?也是4x1零输出吗?
FryAmTheEggman,

1
欢迎。很好的挑战概念,但是通常最好使用沙箱在将挑战想法发布到主要任务之前先敲定它们。
Beefster

@FryAmTheEggman它看起来像OP一直试图让|不是有助于该行的长度,通过使用类似的表示这样(的地方,如果有没有一个管(|),有一个空格)。
暴民埃里克(Erik the Outgolfer)

相关文章:建造
坚固的

1
关于SO的参考问题已不再存在。
阿诺尔德

Answers:


5

果冻,20字节

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

在线尝试!


我知道速度不是规格的一部分,但是在tio上甚至在11x10上也超时。我会对解释以了解其原因感兴趣。
肯尼迪

@NickKennedy太大的输入。对于宽度11,每行可以具有9个不同的平铺之一。对于宽度11和高度10,存在9´= 3486784401可能的墙,包括无效的墙。这就是笛卡尔力量的工作方式。显然,TIO没有时间让我的解决方案计算整个墙壁阵列(60秒后超时)。如果有时间,我会添加解释。
暴民埃里克(Erik the Outgolfer)

谢谢。我稍微看了一下果冻,但此刻我依靠注释解释来了解人们的代码的作用。考虑到时间问题,您的代码蛮力强制解决方案,这是最小化代码需求的明智方法。
尼克·肯尼迪

出于兴趣,我在Jelly中使用代码的第一部分在R代码中重新创建了方法。在网上试用!虽然比您的要长得多,但可以处理更大的数字。请注意,目前无法正确处理1行。我怀疑这可能会更简洁,但我是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

R243231字节

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情况下也能很好地工作。这是我的第一个果冻答案,我怀疑它可以打更多的高尔夫球。理想情况下,我也想更改第一部分,以便时间和内存需求不会随M呈指数增长。


0

05AB1E,42 个字节

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

我几乎不敢发表这个文章,而且绝对可以用一种不同的方法让A LOT打高尔夫球,但是由于花了一段时间才完成,所以我决定还是张贴它,然后从这里开始打高尔夫球。挑战似乎比imo容易,但是我在这里肯定使用了错误的方法,我感到05AB1E可以完成大约25个字节。

在线尝试。注意:它不仅很长,而且效率很低,因为9x4测试用例在TIO上运行大约40秒。

说明:

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

在线尝试!链接是详细版本的代码。可在TIO上处理大小最大为约12的矩形,但可以通过使用位旋转而不是列表交集,以2字节的成本将速度提高大约三倍。说明:

Nθ

输入宽度。

⊞υ⟦⟧

从无砖块开始。

≔⟦⟧η

从没有完成的行开始。

Fυ

循环遍历行。

F⟦²¦³⟧«

循环在砖头上。

≧⁺∧Lι§ι⁰κ

将砖块宽度添加到当前行宽度。

¿⁼κθ⊞ηι

如果这导致输入宽度,则将此行添加到已完成行的列表中。

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

否则,如果它仍然小于输入宽度,则将新行添加到行列表中,从而使它在以后的迭代中被拾取。

≔Eη⟦ι⟧ζ

列出一排墙。

F⊖N«

比高度低一圈。

≔ζι

保存墙壁列表。

≔⟦⟧ζ

清除墙壁列表。

Fι

循环浏览已保存的墙列表。

Fη

循环完成的行。

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

如果可以将行添加到此墙,则将其添加到墙列表。

ILζ

输出墙的最终列表的长度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.