How many ways can a 2 × 1 0 rectangle be filled with 1 × 1 and 2 × 1 tiles?
One such possible tiling is shown below.
Note: Rotations are allowed, so the 2 × 1 tiles can be placed either horizontally or vertically. This problem is intended to be solved with programming.
This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try
refreshing the page, (b) enabling javascript if it is disabled on your browser and,
finally, (c)
loading the
non-javascript version of this page
. We're sorry about the hassle.
A general form is actually an option... Any solution will be of the form f ( n ) = A 1 p 1 n + A 2 p 2 n + A 3 p 3 n , where p 1 , p 2 , p 3 are roots of the equation p 3 − 3 p 2 − p + 1 = 0 . We find numerically that
⎩ ⎪ ⎨ ⎪ ⎧ p 1 ≈ 3 . 2 1 4 3 1 9 7 4 3 3 8 p 2 ≈ − 0 . 6 7 5 1 3 0 8 7 0 5 7 p 3 ≈ 0 . 4 6 0 8 1 1 1 2 7 1 9 Next, we solve the system ⎩ ⎪ ⎨ ⎪ ⎧ A 1 p 1 0 + A 2 p 2 0 + A 3 p 3 0 = 1 A 1 p 1 1 + A 2 p 2 1 + A 3 p 3 1 = 2 A 1 p 1 2 + A 2 p 2 2 + A 3 p 3 2 = 7 and find ⎩ ⎪ ⎨ ⎪ ⎧ A 1 ≈ 0 . 6 6 4 5 9 1 3 8 4 5 3 A 2 ≈ 0 . 2 5 5 9 7 1 8 9 9 3 6 A 3 ≈ 0 . 0 7 9 4 3 6 7 6 1 1 8 Since ∣ p 1 ∣ , ∣ p 2 ∣ , ∣ A 1 ∣ , ∣ A 2 ∣ < 1 , we see that the sum of the second and third terms will always be less than 1 in absolute value; moreover, they decrease rapidly as n increases. Therefore we leave out these terms and simply round A 1 p 1 n to the nearest integer: f ( n ) = [ 0 . 6 6 4 5 9 1 3 8 4 5 3 × 3 . 2 1 4 3 1 9 7 4 3 3 8 n ] .
Thus the solution is f ( 1 0 ) = [ 0 . 6 6 4 5 9 1 3 8 4 5 3 × 3 . 2 1 4 3 1 9 7 4 3 3 8 1 0 ] = 7 8 2 4 3 .
n 0 1 2 3 4 5 6 7 8 9 1 0 1 5 2 0 2 5 3 0 1 0 0 f ( n ) 1 2 7 2 2 7 1 2 2 8 7 3 3 2 3 5 6 7 5 7 3 2 4 3 4 2 7 8 3 4 2 2 6 8 4 6 6 9 6 9 2 1 1 6 2 4 4 6 3 3 . 1 6 1 ⋅ 1 0 1 2 1 . 0 8 4 ⋅ 1 0 1 5 3 . 4 0 0 ⋅ 1 0 5 0
The precise values of p are p = 1 + 3 4 3 cos ( 3 1 ( inv cos 8 3 3 ) + 3 2 π n ) , where n = 0 gives the largest value, p 1 , and n = ± 1 give p 2 and p 3 .
As an aside, to shortcut arriving at the final recurrence, observe that we have g ( n − 1 ) + g ( n ) = f ( n ) − f ( n − 1 ) − f ( n − 2 ) and g ( n ) − g ( n − 1 ) = f ( n − 1 ) , so we know that g ( n ) = 2 [ f ( n ) − f ( n − 1 ) − f ( n − 2 ) ] + [ f ( n − 1 ) ] and g ( n − 1 ) = 2 [ f ( n ) − f ( n − 1 ) − f ( n − 2 ) ] − [ f ( n − 1 ) ] .
Combining these 2, we have
2
[
f
(
n
)
−
f
(
n
−
1
)
−
f
(
n
−
2
)
]
+
[
f
(
n
−
1
)
]
=
g
(
n
)
=
g
(
(
n
+
1
)
−
1
)
=
2
[
f
(
n
+
1
)
−
f
(
n
)
−
f
(
n
−
1
)
]
−
[
f
(
n
)
]
.
Simplifying, we obtain
f
(
n
+
1
)
=
3
f
(
n
)
+
f
(
n
−
1
)
−
f
(
n
−
2
)
.
In general, the idea is to simplify so that we only have terms from one recurrence relation in the equation. However, it is not immediately obvious how this can be done. We were lucky to be able to obtain g ( n ) , g ( n − 1 ) in terms of f ( n ) .
Brilliant!
all of these r math i swear
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Explanation:
grid[x*2+y]
keeps track of whether a tile has been placed or not.
The recursive function
recurs
begins at position
x
and skips to the next empty spot. If there is no such spot, a solution has been found and we return 1.
Otherwise, a single tile is placed at position
x
, and the search continues starting at position
x+1
.
If position
x+1
next immediately below is available, the tile is extended downward and the search continues from there; the number of solutions is added to the number already found.
Likewise, if position
x+2
immediately to the right is available, the tile is extended to the right and another set of solutions is added.
At the end, the new tile is removed.
Here is an alternative approach:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The idea is that every pattern of width n begins with an "indivisible" section of with k , which cannot be cut vertically without dividing a tile.
For k = 1 , there are two inseparable patterns, namely a single vertical tile or two tiles stacked on top of each other.
For k = 2 , there are three inseparable patterns: two horizontal tiles on top of each other; a horizontal tile on top and two individual tiles underneath; or a horizontal tile on bottom and two individual tiles above it.
For k ≥ 3 , there are two inseparable patterns: start with an individual tile in the top-left and bottom-right corner, and fill up with horizontal tiles in an alternating pattern; or start with individual tiles bottom-left and top-right.
Each indivisible section of width k is now followed by any pattern of width n − k to generate the patterns of with n . Thus, the number of patterns f ( n ) of width n satisfies the recursive equation f ( n ) = k = 1 ∑ n a k f ( n − k ) , with a k = 3 for k = 2 , and = 2 for all other k .
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
sir,you're great
The code looks pretty if you use pair recursion:
def f(n):
if n == 0:
return 1
if n == 1:
return 2
return 2*f(n-1) + f(n-2) + 2*g(n-1)
def g(n):
if n == 0:
return 1
if n == 1:
return 1
return f(n-1) + g(n-1)
print(f(10))
>78243
Here f(n) counts the ways to tile a 2 × n , and g(n) counts the ways to tile a 2 × n with a missing corner.
Huh. That is pretty much what I wrote to solve this problem. You even used the same language as I did! :D
def combMain(n):
length = 0
if n == 0:
length += 1
elif n == 1:
length += 2
else:
length += 2*combMain(n - 1) + combMain(n - 2) + 2*combSpec(n - 2)
return length
def combSpec(n):
length = 0
if n == 0:
length += 1
else:
length += combMain(n) + combSpec(n - 1)
return length
This is a regular dynamic programming problem. Let f return the number of ways of filling a rectangle of size n × 2 . If poke is true, one corner is covered.
def f(n, poke):
if n < 0:
return 0
if n == 0:
return 0 if poke else 1
if poke:
return f(n - 1, poke) + f(n - 1, not poke)
return 2 * (f(n - 1, poke) + f(n - 1, not poke)) + f(n - 2, False)
print(f(10, False))
With memoization, this would be a linear time solution. (Search for "memoization decorator" in Google to easily modify this Python code to be linear time.)
What do you want to say?
The problem can be simplifed by looking at the free spaces between various vertical tile placements. This has two benefits: it simplifies the problem to a one dimensional array, and it is just a matter of counting how many ways horizontal tiles can be placed between the verticals tiles. There are exactly 2^10 combinations of vertical tiles. For a gap of 2x1 spaces, the horizontal tiles can be arranged in just two combinations (tile or not tile). The various spaces are tabulated below:
1 2 3 4 5 6 |
|
Anyone seeing a FIBONACCI series arrising from this will be just as pleased as I was to see these useful set of numbers popping up yet again. To recap, each gap between the vertical tiles of size gapSize allows fib[ gapSize ] possible combinations of horizontal tiles. All the rest of the unused tiles are filled with 1x1 tiles by default. To get an total number of possibilities, just multiply each fibonacci number for each appearance (line 18). The code is simply:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
the general results are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
My implementation, which is equal to some recursive implementations in principle, but different in that it uses a for loop instead.
def combRect(n):
lstRect = [0]*(n + 1)
lstSpec = [0]*(n + 1)
lstRect[n] = 1
for ind in range(n, 1, -1):
tVar = lstRect[ind]
lstRect[ind - 1] += 2*tVar
lstRect[ind - 2] += tVar
lstSpec[ind - 1] += 2*tVar
tVar = lstSpec[ind]
if tVar > 0:
lstRect[ind - 1] += tVar
lstSpec[ind - 1] += tVar
lstRect[ind] = 0
lstSpec[ind] = 0
output = lstRect[0] + lstSpec[0]
if n >= 1:
output += 2*lstRect[1] + lstSpec[1]
return output
Python recursive solution:
def countWays(top, bottom):
assert(top >= bottom)
assert(top >= 0)
assert(bottom >= 0)
assert(top == bottom or top == bottom + 1)
answer = -1
if top == bottom == 0:
answer = 1
elif top == bottom:
if top == 1:
answer = 2
else:
answer = 2 * countWays(top - 1, bottom - 1) + 2 * countWays(top - 1, bottom - 2) + countWays(top - 2, bottom - 2)
else:
if top == 1:
answer = 1
elif top == 2:
answer = 3
else:
answer = countWays(top - 1, bottom) + countWays(top - 1, bottom - 1)
#print("{} {} -> {}".format(top, bottom, answer))
return answer
print(countWays(10, 10))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
I've fixed the vertical tiles first, these are the possible combinations ( v e r t i c a l T i l e s c o l u m n s ) for verticalTiles ∈ [ 0 , c o l u m n s ] . Then the horizontal tiling is defined by the recursive function tilingsForRow squared on the spaces between vertical tiles (or at the end of the board)
1 2 3 4 5 6 7 8 9 10 11 |
|
I like pointing out what language the code is in for us non-programmers, Thanks.
Log in to reply
Hi, I've added the language in the header of the code block
First consider the placement of vertical 2 x 1 tiles. For each of the 1 0 columns, a vertical tile can be there or not there, for 2 1 0 possibilities. If we represent a present vertical tile as 1 , and a non-present vertical tile as 0 , we can use binary numbers to analyze every possibility.
Now between vertical tiles, there may be room for 1 x 1 tiles and horizontal 2 x 1 tiles in a given row. If n is the number of columns available between vertical tiles (or the length of the string of zeros in the binary representation), then k horizontal 2 x 1 tiles can fit in that space in one row in ∑ k = 0 ⌊ 2 n ⌋ ( k n − k ) ways, which happens to be the sum of shallow diagonals in Pascal's triangle, which is equal to the Fibonacci number F n + 1 . Since the second row would have the same number of horizontal tilings as the first row, each string of n zeros would have F n + 1 2 possible tilings.
We can therefore use binary numbers and the Fibonacci sequence in a computer program (similar to the one below) to find that there are 7 8 2 4 3 ways that a 2 x 1 0 rectangle can be filled with 1 x 1 and 2 x 1 tiles.
# Tiling Problem
# Python 2.7.3
def TilingPossibilities(columns):
# generate a Fibonacci list
Fibonacci = [1, 1]
for a in range(2, columns + 1):
Fibonacci.append(Fibonacci[a - 2] + Fibonacci[a - 1])
# go through all possibilities (binary patterns) of vertical tile
# placements in the first and second row, where 1 represents a
# vertical tile and 0 represents no vertical tile
totalpossibilities = 0
for a in range(0, 2 ** columns):
binarypattern = "{0:b}".format(a).zfill(columns)
# go through each binary pattern and find strings of zeros
zerostring = 1
binaryproduct = 1
for b, c in enumerate(binarypattern[:-1]):
if c == "0" and c == binarypattern[b + 1]:
# the string of zeros continues, so increase its counter
zerostring += 1
elif c == "0" and c != binarypattern[b + 1]:
# the string of zeros is broken, so calculate the number of
# tiling possibilities (binaryproduct) in that string using
# the Fibonacci pattern
binaryproduct *= (Fibonacci[zerostring] ** 2)
zerostring = 1
# if the binary pattern ends in zero, calculate the number of tiling
# possibilities (binaryproduct) using the Fibonacci pattern
if binarypattern[-1] == "0":
binaryproduct *= (Fibonacci[zerostring] ** 2)
# add the number of tiling possibilities (binaryproduct) for each
# binary pattern to the total possibilities
totalpossibilities += binaryproduct
return totalpossibilities
print TilingPossibilities(10)
Let f [ n ] denotes the way of tiling for 2 × n with a vertical 2 × 1 tile at the end. Therefore we are looking for f [ 1 1 ] .
Now, let's enumerate the possible last but one vertical 2 × 1 tile, and since there are no vertical 2 × 1 tiles between them, it reduces to a simple question of filling two 1 × n with 1 × 1 and 2 × 1 tiles, the answer to which is the Fibonacci sequence.
Therefore we have the following formula:
f [ n ] = ∑ i = 0 n − 1 f [ i ] F [ n − i ] 2
where F [ k ] is the k -th element of the Fibonacci sequence, starting F [ 0 ] = 1 and F [ 1 ] = 1 .
F = [1,1,2,3,5,8,13,21,34,55,89]
f = [1]
for i in range(11):
f.append(0)
for j in range(i+1):
f[i+1]+=f[j]*F[i-j]*F[i-j]
print(f[11])
By using the solutions for a board of size 2 × ( n − 1 ) , it is possible to fill the board of size 2 × n from one end, up until but not including the two tile spaces at the opposite end. (For the purpose of clarity, I will be filling from the left end of the board in my explanation, with the two free spaces remaining on the right end.)
By filling the board in this manner, we can work out the total number of solutions for a board of size 2 × n using the following methods:
There are some more things we can consider to make working this out much simpler:
We can now count the number of solutions for a board, by adding these sets together:
Let f ( n ) be the number of solutions for a board of size 2 × n . Let g ( n ) be the number of solutions for a board with a 1 × 1 tile in a specific right-end corner.
f ( n ) = f ( n − 1 ) × 2 + ( g ( n − 1 ) + f ( n − 2 ) ) × 2 + f ( n − 2 )
To Simplify:
f ( n ) = ( f ( n − 1 ) + g ( n − 1 ) ) × 2 + f ( n − 2 ) ) × 3
By counting the solutions of smaller boards, we know that f ( 1 ) = 2 , f ( 2 ) = 7 , and g ( 2 ) = 1 .
We can now work out the number of solutions for larger boards, eventually getting us to f ( 1 0 ) = 7 8 2 4 3 (If you're lazy like me, you can just use a spreadsheet to quickly calculate the number of solutions for larger boards).
Problem Loading...
Note Loading...
Set Loading...
If your computer is broken and you're really good at arithmetic, you can do the following:
Let f ( n ) be the number of ways to tile a 2 × n rectangular board in the desired way. Let g ( n ) be the number of ways to tile a 2 × n rectangular board that is missing a corner.
Note the base cases f ( 1 ) = 2 and g ( 1 ) = 1 .
For brevity, denote a 2 × 1 tile as a domino.
We now find a recursive relation for f ( n ) . We take a bunch of cases. Assume n > 1 .
If the topleft cell is covered by a 1 × 1 tile, there are g ( n ) ways to tile the rest of the board.
If the topleft cell is covered by a vertical domino, there are f ( n − 1 ) ways to tile the rest of the board.
If the topleft cell is covered by a horizontal domino, then...
If the bottomleft cell is covered by a 1 × 1 tile, there are g ( n − 1 ) ways to tile the rest of the board.
If the bottomleft cell is covered by a horizontal domino, then there are f ( n − 2 ) ways to tile the rest of the board.
We now find a recursive relation for g ( n ) . Assume WLOG that it is the bottomleft cell that is missing.
If the topleft cell is covered by a 1 × 1 tile, there are f ( n − 1 ) ways to tile the rest of the board.
If the topleft cell is covered by a horizontal domino, there are g ( n − 1 ) ways to tile the rest of the board.
We deduce that f ( n ) = f ( n − 1 ) + f ( n − 2 ) + g ( n − 1 ) + g ( n ) , and g ( n ) = f ( n − 1 ) + g ( n − 1 ) . By substitution, f ( n ) = f ( n − 2 ) + 2 g ( n ) .
Note that: g ( n ) = f ( n − 1 ) + g ( n − 1 ) = f ( n − 1 ) + f ( n − 2 ) + g ( n − 2 ) = f ( n − 1 ) + f ( n − 2 ) + f ( n − 3 ) + ⋯ + f ( 1 ) + g ( 1 ) But g ( 1 ) = 1 , so: g ( n ) = 1 + i = 1 ∑ n − 1 f ( i )
We can now substitute g ( n ) to get: f ( n ) = f ( n − 2 ) + 2 ( 1 + i = 1 ∑ n − 1 f ( i ) ) And: f ( n − 1 ) = f ( n − 3 ) + 2 ( 1 + i = 1 ∑ n − 2 f ( i ) )
Subtracting these two equations and rearranging terms gets us: f ( n ) = 3 f ( n − 1 ) + f ( n − 2 ) − f ( n − 3 )
Unfortunately, the characteristic polynomial for the recurrence has no obvious roots, so finding the general form isn't really an option. We now have to proceed by hand. We'll need three base cases. It is easiest to use f ( 0 ) = 1 , f ( 1 ) = 2 , f ( 2 ) = 7 if you trust the reasoning "there is exactly one way to tile nothing". If not, it is not too hard to derive f ( 3 ) = 2 2 . Taking your preferred bases and using the recurrence gets us f ( 1 0 ) = 7 8 2 4 3 .