長方形内のユニークなレンガのタイル


13

私はStackoverflowを閲覧していて、MxN長方形のタイリングに関するこの質問を見、ゴルフに最適だと思いました。ここにタスクがあります。

次元MとNが与えられた場合、MxNの長方形(Nは列ではなく行の数です。実際には重要ではありません)がこれらの制約の下でタイル化できるユニークな方法を出力するプログラムを書きます。

  1. すべてのタイルは2x1または3x1です
  2. すべてのタイルは行内にとどまります(つまり、すべて水平です)
  3. 隣接する2行ごとに、2つの端を除き、タイルを配置しないでください。
  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?また、4x1ゼロの出力はありますか?
FryAmTheEggman

1
ようこそ。素敵なチャレンジコンセプトですが、通常はメインに投稿する前に、サンドボックスを使用してチャレンジアイデアを打ち出すことが最善です。
ビーフスター

OPを作ってみましたように見え@FryAmTheEggman |様表現使用して、複数行の長さに寄与しないこの(パイプ(そこではない場合、|)、スペースがあります)。
エリックアウトゴルファー


1
SOで参照されている質問はもうありません。
アーナルド

回答:


5

ゼリー、20バイト

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

オンラインでお試しください!


速度は仕様の一部ではないことは知っていますが、tioで実行すると11x10でもタイムアウトになりました。理由を理解するための説明に興味があります。
ニックケネディ

@NickKennedyそれは入力が大きすぎます。幅11の場合、各行には9つの異なるタイルのいずれかを使用できます。幅11および高さ10の場合、無効な壁を含む9¹⁰= 3486784401の壁があります。それがデカルトの力の働きです。明らかに、TIOには、ソリューションが壁の配列全体を計算する時間はありません(60秒後にタイムアウトします)。時間があるときに説明を追加します。
エリックアウトゴルファー

ありがとう。私はゼリーを少し見ましたが、現時点では、人々のコードが何をするのかを理解するためにコメント付きの説明に頼っています。時間の問題を考えると、あなたのコードが総当たりでソリューションを強制することを想定していました。これは、コード要件を最小限に抑える賢明な方法です。
ニックケネディ

興味深いことに、コードの最初の部分を使用して、RコードのメソッドをJellyで再作成しました。オンラインでお試しください!それはあなたのものよりもかなり長いですが、より大きな数を処理します。現在、1行を適切に処理していないことに注意してください。もっと簡潔かもしれないと思うが、私はゼリーは初めてだ。
ニックケネディ

4

JavaScript(ES6)、119110106  96  91バイト

NM

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

R243 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でもうまく機能します。これは私の最初のゼリーの回答であり、もっとゴルフができると思います。また、時間とメモリの要件がMに指数関数的に比例しないように、最初のセクションを変更するのが理想的です。


0

05AB1E、42 バイト

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

私はこれを投稿することをほとんど恥ずかしく思っており、別のアプローチで間違いなくゴルフをすることができますが、完了するのに時間がかかったので、とにかく投稿してここからゴルフすることを決めました。チャレンジはよりも簡単に見えますが、ここでは間違いなく間違ったアプローチを使用しており、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バイトのコストで約3倍高速化できます。説明:

Nθ

幅を入力します。

⊞υ⟦⟧

レンガのない列から始めます。

≔⟦⟧η

完了した行がない状態で開始します。

Fυ

行をループします。

F⟦²¦³⟧«

レンガをループします。

≧⁺∧Lι§ι⁰κ

ブリックの幅を現在の行の幅に追加します。

¿⁼κθ⊞ηι

これにより入力幅が得られる場合、この行を完了した行のリストに追加します。

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

それ以外の場合、これがまだ入力幅よりも小さい場合は、新しい行を行のリストに追加します。これにより、後の反復で選択されます。

≔Eη⟦ι⟧ζ

1列の壁のリストを作成します。

F⊖N«

高さよりも1つ以上ループします。

≔ζι

壁のリストを保存します。

≔⟦⟧ζ

壁のリストをクリアします。

Fι

保存された壁のリストをループします。

Fη

完了した行をループします。

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

この壁に行を追加できる場合は、壁のリストに追加します。

ILζ

壁の最終リストの長さを出力します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.