사각형 내의 독특한 벽돌 타일링


13

나는 Stackoverflow를 탐색 하고 MxN 사각형을 타일링하는 것에 대한 이 질문을 보았고 이것이 골프에 좋을 것이라고 생각했습니다. 다음은 과제입니다.

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
타일 ​​크기에 대한 설명은 사각형의 크기와 다른 규칙을 사용하는 것 같습니다. 타일은 실제로 2x13x1? 또한 출력은 4x10입니까?
FryAmTheEggman

1
어서 오십시오. 좋은 챌린지 개념이지만, 샌드 박스 를 사용하여 챌린지 아이디어를 메인에 게시하기 전에 망치 는 것이 가장 좋습니다 .
Beefster

영업 이익은 만들려고 한 것 같습니다 @FryAmTheEggman |같은 표현을 사용하여,의 행의 길이에 기여하지 (파이프 (이 아니라면 |), 공간있다).
Outgolfer Erik


1
SO에 대한 참조 질문은 더 이상 없습니다.
Arnauld

답변:


5

젤리 , 20 바이트

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

온라인으로 사용해보십시오!


속도가 사양의 일부가 아니라는 것을 알고 있지만 tio에서 실행할 때 11x10에서도 시간이 초과되었습니다. 이유를 이해하기위한 설명에 관심이 있습니다.
Nick Kennedy

@NickKennedy 입력이 너무 큽니다. 너비 11의 경우 각 행은 9 개의 서로 다른 타일 중 하나를 가질 수 있습니다. 너비 11 및 높이 10의 경우 유효하지 않은 벽을 포함하여 9¹⁰ = 3486784401 개의 가능한 벽이 있습니다. 이것이 직교 힘이 작동하는 방식입니다. 분명히 TIO는 내 솔루션이 벽의 전체 배열을 계산할 시간이 없습니다 (60 초 후에 시간 초과). 시간이되면 설명을 추가하겠습니다.
Outgolfer Erik

감사. 나는 젤리를 조금 보았지만, 지금은 사람들의 코드가하는 일을 이해하기 위해 주석이 달린 설명에 의존합니다. 코드 문제가 솔루션을 강제하는 시간 문제를 감안할 때 코드 요구 사항을 최소화하는 합리적인 방법입니다.
Nick Kennedy

흥미롭게도 Jelly에서 코드의 첫 부분을 사용하여 R 코드의 메소드를 다시 작성했습니다. 그것은에있어 온라인으로보십시오! 그리고 그것은 당신보다 상당히 길지만 더 큰 숫자를 처리합니다. 현재 1 행을 올바르게 처리하지 못합니다. 나는 그것이 더 간결 할 수 있다고 생각하지만 젤리를 처음 사용합니다.
Nick Kennedy

4

자바 스크립트 (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

온라인으로 사용해보십시오!

댓글

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 , 243231 바이트

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

나는 이것을 게시하는 것이 너무 부끄러워서 다른 접근법으로 ALOT에 의해 확실히 골프를 칠 수는 있지만 완료하는 데 시간이 걸리기 때문에 어쨌든 게시하고 여기에서 골프를 타기로 결정했습니다. 도전은 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 ​​크기의 사각형에서 작동하지만 목록 교차 대신 비트 twiddling을 사용하면 2 바이트의 비용으로 약 3 배 더 빠를 수 있습니다. 설명:

Nθ

너비를 입력하십시오.

⊞υ⟦⟧

벽돌이없는 줄로 시작하십시오.

≔⟦⟧η

완료된 행없이 시작하십시오.

Fυ

행을 반복합니다.

F⟦²¦³⟧«

벽돌을 반복합니다.

≧⁺∧Lι§ι⁰κ

벽돌 너비를 현재 행 너비에 추가하십시오.

¿⁼κθ⊞ηι

입력 너비가 발생하면이 행을 완료된 행 목록에 추가하십시오.

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

그렇지 않으면 여전히 입력 너비보다 작 으면 새 행을 행 목록에 추가하여 나중에 반복하여 선택합니다.

≔Eη⟦ι⟧ζ

한 줄의 벽 목록을 만듭니다.

F⊖N«

높이보다 하나 더 낮게 반복하십시오.

≔ζι

벽 목록을 저장하십시오.

≔⟦⟧ζ

벽 목록을 지우십시오.

Fι

저장된 벽 목록을 반복합니다.

Fη

완성 된 행을 반복합니다.

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

이 벽에 행을 추가 할 수 있으면 벽을 벽리스트에 추가하십시오.

ILζ

벽의 최종 목록의 길이를 출력합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.