Given a "2 x n" board and tiles of size "2 x 1", the task is to count the number of ways to tile the given board using the 2 x 1 tiles. A tile can either be placed horizontally i.e., as a 1 x 2 tile or vertically i.e., as 2 x 1 tile.
Examples:
Input: n = 4
Output: 5
Explanation: For a 2 x 4 board, there are 5 ways
- All 4 vertical (1 way)
- All 4 horizontal (1 way)
- 2 vertical and 2 horizontal (3 ways)
Input: n = 3
Output: 3
Explanation: We need 3 tiles to tile the board of size 2 x 3.
We can tile the board using the following ways
- Place all 3 tiles vertically.
- Place 1 tile vertically and the remaining 2 tiles horizontally (2 ways)
Using Recursion - O(2^n) Time and O(n) Space
The idea is to explore two possible ways to place tiles on a 2 x n board: either placing a vertical tile (2 x 1) which reduces the problem to filling a 2 x (n-1) board, or placing two horizontal tiles (1 x 2) which reduces the problem to filling a 2 x (n-2) board. At each step, we sum these two possibilities, creating a recursive solution where the total number of ways to tile the board is the sum of ways for the smaller subproblems.
Mathematically the recurrence relation will look like the following:
numberOfWays(n) = numberOfWays(n-1) + numberOfWays(n-2).
Base Cases:
- numberOfWays(n) = 1, if n = 0.
- numberOfWays(n) = 0, if n < 0.
C++
// C++ program to implement
// tiling problem using recursion
#include <bits/stdc++.h>
using namespace std;
int numberOfWays(int n) {
// Base Case: invalid n
if (n<0) return 0;
// Base case: valid n
if (n == 0) return 1;
int ans = 0;
// count ways if one tile
// is placed vertically
ans = numberOfWays(n-1);
// count ways if two tiles
// are placed horizontly.
ans += numberOfWays(n-2);
return ans;
}
int main() {
int n = 4;
cout<<numberOfWays(n);
return 0;
}
Java
// Java program to implement
// tiling problem using recursion
class GfG {
static int numberOfWays(int n) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n == 0) return 1;
int ans = 0;
// count ways if one tile
// is placed vertically
ans = numberOfWays(n - 1);
// count ways if two tiles
// are placed horizontally.
ans += numberOfWays(n - 2);
return ans;
}
public static void main(String[] args) {
int n = 4;
System.out.println(numberOfWays(n));
}
}
Python
# Python program to implement
# tiling problem using recursion
def numberOfWays(n):
# Base Case: invalid n
if n < 0:
return 0
# Base case: valid n
if n == 0:
return 1
ans = 0
# count ways if one tile
# is placed vertically
ans = numberOfWays(n - 1)
# count ways if two tiles
# are placed horizontally.
ans += numberOfWays(n - 2)
return ans
if __name__ == "__main__":
n = 4
print(numberOfWays(n))
C#
// C# program to implement
// tiling problem using recursion
using System;
class GfG {
static int numberOfWays(int n) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n == 0) return 1;
int ans = 0;
// count ways if one tile
// is placed vertically
ans = numberOfWays(n - 1);
// count ways if two tiles
// are placed horizontally.
ans += numberOfWays(n - 2);
return ans;
}
static void Main(string[] args) {
int n = 4;
Console.WriteLine(numberOfWays(n));
}
}
JavaScript
// JavaScript program to implement
// tiling problem using recursion
function numberOfWays(n) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n === 0) return 1;
let ans = 0;
// count ways if one tile
// is placed vertically
ans = numberOfWays(n - 1);
// count ways if two tiles
// are placed horizontally.
ans += numberOfWays(n - 2);
return ans;
}
const n = 4;
console.log(numberOfWays(n));
Using Top-Down DP (Memoization) - O(n) Time and O(n) Space
If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:
1. Optimal Substructure: Number of ways to add i'th tile, i.e., numberOfWays(i), depends on the optimal solutions of the subproblems numberOfWays(i-1), and numberOfWays(i-2). By comparing these optimal substructures, we can efficiently calculate the number of ways to add i' th tile.
2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times. For example, for n = 4, numberOfWays(3) and numberOfWays(2) are called. numberOfWays(3) again calls numberOfWays(2) which leads to Overlapping Subproblems.
- There are only is one parameter: i that changes in the recursive solution. So we create a 1D array of size n+1 for memoization.
- We initialize this array as -1 to indicate nothing is computed initially.
- Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems.
C++
// C++ program to implement
// tiling problem using memoization
#include <bits/stdc++.h>
using namespace std;
int countRecur(int n, vector<int> &memo) {
// Base Case: invalid n
if (n<0) return 0;
// Base case: valid n
if (n == 0) return 1;
// If value is memoized
if (memo[n] != -1) return memo[n];
int ans = 0;
// count ways if one tile
// is placed vertically
ans = countRecur(n-1, memo);
// count ways if two tiles
// are placed horizontly.
ans += countRecur(n-2, memo);
return memo[n] = ans;
}
int numberOfWays(int n) {
vector<int> memo(n+1, -1);
return countRecur(n, memo);
}
int main() {
int n = 4;
cout<<numberOfWays(n);
return 0;
}
Java
// Java program to implement
// tiling problem using memoization
import java.util.Arrays;
class GfG {
static int countRecur(int n, int[] memo) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n == 0) return 1;
// If value is memoized
if (memo[n] != -1) return memo[n];
int ans = 0;
// count ways if one tile
// is placed vertically
ans = countRecur(n - 1, memo);
// count ways if two tiles
// are placed horizontally.
ans += countRecur(n - 2, memo);
return memo[n] = ans;
}
static int numberOfWays(int n) {
int[] memo = new int[n + 1];
Arrays.fill(memo, -1);
return countRecur(n, memo);
}
public static void main(String[] args) {
int n = 4;
System.out.println(numberOfWays(n));
}
}
Python
# Python program to implement
# tiling problem using memoization
def countRecur(n, memo):
# Base Case: invalid n
if n < 0:
return 0
# Base case: valid n
if n == 0:
return 1
# If value is memoized
if memo[n] != -1:
return memo[n]
ans = 0
# count ways if one tile
# is placed vertically
ans = countRecur(n - 1, memo)
# count ways if two tiles
# are placed horizontally.
ans += countRecur(n - 2, memo)
memo[n] = ans
return memo[n]
def numberOfWays(n):
memo = [-1] * (n + 1)
return countRecur(n, memo)
if __name__ == "__main__":
n = 4
print(numberOfWays(n))
C#
// C# program to implement
// tiling problem using memoization
using System;
class GfG {
static int countRecur(int n, int[] memo) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n == 0) return 1;
// If value is memoized
if (memo[n] != -1) return memo[n];
int ans = 0;
// count ways if one tile
// is placed vertically
ans = countRecur(n - 1, memo);
// count ways if two tiles
// are placed horizontally.
ans += countRecur(n - 2, memo);
return memo[n] = ans;
}
static int numberOfWays(int n) {
int[] memo = new int[n + 1];
for (int i = 0; i <= n; i++) {
memo[i] = -1;
}
return countRecur(n, memo);
}
static void Main(string[] args) {
int n = 4;
Console.WriteLine(numberOfWays(n));
}
}
JavaScript
// JavaScript program to implement
// tiling problem using memoization
function countRecur(n, memo) {
// Base Case: invalid n
if (n < 0) return 0;
// Base case: valid n
if (n === 0) return 1;
// If value is memoized
if (memo[n] !== -1) return memo[n];
let ans = 0;
// count ways if one tile
// is placed vertically
ans = countRecur(n - 1, memo);
// count ways if two tiles
// are placed horizontally.
ans += countRecur(n - 2, memo);
return memo[n] = ans;
}
function numberOfWays(n) {
const memo = Array(n + 1).fill(-1);
return countRecur(n, memo);
}
const n = 4;
console.log(numberOfWays(n));
Using Bottom-Up DP (Tabulation) - O(n) Time and O(n) Space
The idea is to fill the DP table based on previous values. For each tile, we either add it vertically or horizontally to compute number of ways. The table is filled in an iterative manner from i = 2 to n.
The dynamic programming relation is as follows:
- dp[i] = dp[i-1] + dp[i-2]
C++
// C++ program to implement
// tiling problem using tabulation
#include <bits/stdc++.h>
using namespace std;
int numberOfWays(int n) {
if (n==0 || n==1) return 1;
vector<int> dp(n+1);
dp[0] = 1;
dp[1] = 1;
for (int i=2; i<=n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
int main() {
int n = 4;
cout<<numberOfWays(n);
return 0;
}
Java
// Java program to implement
// tiling problem using tabulation
import java.util.*;
class GfG {
static int numberOfWays(int n) {
if (n == 0 || n == 1) return 1;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
public static void main(String[] args) {
int n = 4;
System.out.println(numberOfWays(n));
}
}
Python
# Python program to implement
# tiling problem using tabulation
def numberOfWays(n):
if n == 0 or n == 1:
return 1
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
if __name__ == "__main__":
n = 4
print(numberOfWays(n))
C#
// C# program to implement
// tiling problem using tabulation
using System;
class GfG {
static int numberOfWays(int n) {
if (n == 0 || n == 1) return 1;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
static void Main(string[] args) {
int n = 4;
Console.WriteLine(numberOfWays(n));
}
}
JavaScript
// JavaScript program to implement
// tiling problem using tabulation
function numberOfWays(n) {
if (n === 0 || n === 1) return 1;
const dp = new Array(n + 1).fill(0);
dp[0] = 1;
dp[1] = 1;
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
const n = 4;
console.log(numberOfWays(n));
Using Space Optimized DP - O(n) Time and O(1) Space
In previous approach of dynamic programming we have derived the relation between states as given below:
- dp[i] = dp[i-1] + dp[i-2]
If we observe that for calculating current dp[i] state we only need dp[i-1] and dp[i-2]. There is no need to store all the previous states just two previous state is used to compute result.
C++
// C++ program to implement
// tiling problem using space optimised dp
#include <bits/stdc++.h>
using namespace std;
int numberOfWays(int n) {
if (n==0 || n==1) return 1;
int prev2 = 1;
int prev1 = 1;
for (int i=2; i<=n; i++) {
int curr = prev1+prev2;
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
int main() {
int n = 4;
cout<<numberOfWays(n);
return 0;
}
Java
// Java program to implement
// tiling problem using space optimised dp
import java.util.*;
class GfG {
static int numberOfWays(int n) {
if (n == 0 || n == 1) return 1;
int prev2 = 1;
int prev1 = 1;
for (int i = 2; i <= n; i++) {
int curr = prev1 + prev2;
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
public static void main(String[] args) {
int n = 4;
System.out.println(numberOfWays(n));
}
}
Python
# Python program to implement
# tiling problem using space optimised dp
def numberOfWays(n):
if n == 0 or n == 1:
return 1
prev2 = 1
prev1 = 1
for i in range(2, n + 1):
curr = prev1 + prev2
prev2 = prev1
prev1 = curr
return prev1
if __name__ == "__main__":
n = 4
print(numberOfWays(n))
C#
// C# program to implement
// tiling problem using space optimised dp
using System;
class GfG {
static int numberOfWays(int n) {
if (n == 0 || n == 1) return 1;
int prev2 = 1;
int prev1 = 1;
for (int i = 2; i <= n; i++) {
int curr = prev1 + prev2;
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
static void Main(string[] args) {
int n = 4;
Console.WriteLine(numberOfWays(n));
}
}
JavaScript
// JavaScript program to implement
// tiling problem using space optimised dp
function numberOfWays(n) {
if (n === 0 || n === 1) return 1;
let prev2 = 1;
let prev1 = 1;
for (let i = 2; i <= n; i++) {
let curr = prev1 + prev2;
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
const n = 4;
console.log(numberOfWays(n));
Related articles:
Similar Reads
The Celebrity Problem
Given a square matrix mat[][] of size n x n, such that mat[i][j] = 1 means ith person knows jth person, the task is to find the celebrity. A celebrity is a person who is known to all but does not know anyone. Return the index of the celebrity, if there is no celebrity return -1.Note: Follow 0-based
15 min read
Josephus Problem Using Bit Magic
The Problem This problem is named after Flavius Josephus a Jewish historian who fought against the Romans. According to Josephus he and his group of Jewish soldiers were cornered & surrounded by the Romans inside a cave, and they choose to murder and suicide inside of surrender and capture. They
14 min read
Organizing Tournament Problem
Given a positive integer N representing the count of players playing the game. The game is played between two teams such that each team consists of at least one player but the total count of players in the game must be N. The game lasts in exactly 30 minutes, the task is to check if all players will
8 min read
The Celebrity Problem | Set-3
In a party of N people, only one person is known to everyone. Such a person may be present at the party, if yes, (s)he doesnât know anyone in the party. We can only ask questions like âdoes A know B? â. Find the stranger (celebrity) in the minimum number of questions.We can describe the problem inpu
4 min read
Ways to remove TLE
While solving problems on any online judge sometimes it might get Time Limit Exceeded. Below are some of the ways to optimize the code: Minimize the use of loops inside loops i.e., Nested Loops: For Example: for(i = 0 ; i < n ; i++) { for(j = 0 ; j < n ; j++) { // Your Code } }The above code w
2 min read
Puzzle | Message Spreading
There are n students in a class, each in possession of a different funny story. As the students were getting bored in the class, they decided to come up with a game so that they can pass their time. They want to share the funny stories with each other by sending electronic messages. Assume that a se
3 min read
CSES Solutions - Coin Piles
You are given Q queries. In each query, you have two coin piles containing A and B coins. On each move, you can either remove one coin from the left pile and two coins from the right pile, or two coins from the left pile and one coin from the right pile. Your task is to efficiently find out if you c
7 min read
Assign Mice to Holes
There are N Mice and N holes are placed in a straight line. Each hole can accommodate only 1 mouse. A mouse can stay at his position, move one step right from x to x + 1, or move one step left from x to x -1. Any of these moves consumes 1 minute. Assign mice to holes so that the time when the last m
8 min read
CSES Solutions - Another Game
There are n heaps of coins and two players who move alternately. On each move, a player selects some of the nonempty heaps and removes one coin from each heap. The player who removes the last coin wins the game. Your task is to find out who wins if both players play optimally. Examples: Input: N = 3
5 min read
Program to solve the Alligation Problem
Write a program to find the ratio in which a shopkeeper will mix two types of rice worth Rs. X kg and Rs. Y kg, so that the average cost of the mixture is Rs. Z kg. Examples: Input: X = 50, Y = 70, Z = 65Output: Ratio = 1:3 Input: X = 1000, Y = 2000, Z = 1400Output: Ratio = 3:2 According to Alligati
6 min read