There are 'p' balls of type P, 'q' balls of type Q and 'r' balls of type R. Using the balls we want to create a straight line such that no two balls of the same type are adjacent.
Examples :
Input: p = 1, q = 1, r = 0
Output: 2
Explanation: There are only two arrangements PQ and QPInput: p = 1, q = 1, r = 1
Output: 6
Explanation: There are only six arrangements PQR, QPR, QRP, RQP, PRQ and RPQInput: p = 2, q = 1, r = 1
Output: 12
Explanation: There are twelve arrangements PQRP, PRQP, QPRP, RPQP, PQPR, PRPQ, QPQR, RQRP, PQRQ, QRQP, RPQR, and QRPR
Table of Content
Using Recursion – O(3^n) Time and O(n) Space
To solve this problem, we use a recursive approach, placing the last ball as one of three types. Each ball type is represented by a digit in the recurrence relation: 0 for P, 1 for Q, and 2 for R. If the last ball is of type P (0), the next ball must be of type Q or R, and similarly for the last balls of type Q (1) and R (2).
Recurrence Relation:
- if the last ball is of type P: countWays(p, q, r, last) = countWays(p-1, q, r, 1) + countWays(p-1, q, r, 2)
- if the last ball is of type Q: countWays(p, q, r, last) = countWays(p, q-1, r, 0) + countWays(p, q-1, r, 2)
- if the last ball is of type R: countWays(p, q, r, last) = countWays(p, q, r-1, 0) + countWays(p, q-1, r-1, 1)
Base Cases:
if (p < 0), (q < 0) or (r < 0) then countWays(p, q, r, last) = 0. if only one ball ramains of specific type, then:
- countWays(p, q, r, 0) = 1 if p=1 and q=0 and r=0
- countWays(p, q, r, 1) = 1 if p=0 and q=1 and r=0
- countWays(p, q, r, 2) = 1 if p=0 and q=0 and r=1
// C++ program to count number of ways to arrange three
// types of balls such that no two balls of same color
// are adjacent to each other using recursion
#include <iostream>
using namespace std;
// Returns count of arrangements where last placed ball is
// 'last'. 'last' is 0 for 'p', 1 for 'q' and 2 for 'r'
int countUtil(int p, int q, int r, int last) {
// if number of balls of any color becomes less
// than 0 the number of ways arrangements is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// If last ball required is of type P and the number
// of balls of P type is 1 while number of balls of
// other color is 0 the number of ways is 1.
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
// Same case as above for 'q' and 'r'
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// if last ball required is P and the number of ways is
// the sum of number of ways to form sequence with 'p-1' P
// balls, q Q Balls and r R balls ending with Q and R.
if (last == 0)
return countUtil(p - 1, q, r, 1) + countUtil(p - 1, q, r, 2);
// Same as above case for 'q' and 'r'
if (last == 1)
return countUtil(p, q - 1, r, 0) + countUtil(p, q - 1, r, 2);
if (last == 2)
return countUtil(p, q, r - 1, 0) + countUtil(p, q, r - 1, 1);
}
// Returns count of required arrangements
int countWays(int p, int q, int r) {
// Three cases arise:
// Last required balls is type P
// Last required balls is type Q
// Last required balls is type R
return countUtil(p, q, r, 0) + countUtil(p, q, r, 1) + countUtil(p, q, r, 2);
}
int main() {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
cout << res << endl;
return 0;
}
// Java program to count number
// of ways to arrange three types of
// balls such that no two balls of
// same color are adjacent to each other
// using recursion
import java.io.*;
import java.util.*;
class GfG {
// Returns count of arrangements
// where last placed ball is
// 'last'. 'last' is 0 for 'p',
// 1 for 'q' and 2 for 'r'
static int countUtil(int p, int q, int r, int last) {
// if number of balls of any
// color becomes less than 0
// the number of ways arrangements is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// If last ball required is
// of type P and the number
// of balls of P type is 1
// while number of balls of
// other color is 0 the number
// of ways is 1.
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
// Same case as above for 'q' and 'r'
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// if last ball required is P
// and the number of ways is
// the sum of number of ways
// to form sequence with 'p-1' P
// balls, q Q Balls and r R balls
// ending with Q and R.
if (last == 0)
return countUtil(p - 1, q, r, 1)
+ countUtil(p - 1, q, r, 2);
// Same as above case for 'q' and 'r'
if (last == 1)
return countUtil(p, q - 1, r, 0)
+ countUtil(p, q - 1, r, 2);
if (last == 2)
return countUtil(p, q, r - 1, 0)
+ countUtil(p, q, r - 1, 1);
return 0;
}
// Returns count of required arrangements
static int countWays(int p, int q, int r) {
// Three cases arise:
// Last required balls is type P
// Last required balls is type Q
// Last required balls is type R
return countUtil(p, q, r, 0) + countUtil(p, q, r, 1)
+ countUtil(p, q, r, 2);
}
public static void main(String[] args) {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
System.out.print(res);
}
}
# Python3 program to count
# number of ways to arrange
# three types of balls such
# that no two balls of same
# color are adjacent to each
# other using recursion
# Returns count of arrangements
# where last placed ball is
# 'last'. 'last' is 0 for 'p',
# 1 for 'q' and 2 for 'r'
def countUtil(p, q, r, last):
# if number of balls of
# any color becomes less
# than 0 the number of
# ways arrangements is 0.
if (p < 0 or q < 0 or r < 0):
return 0
# If last ball required is
# of type P and the number
# of balls of P type is 1
# while number of balls of
# other color is 0 the number
# of ways is 1.
if (p == 1 and q == 0
and r == 0 and last == 0):
return 1
# Same case as above
# for 'q' and 'r'
if (p == 0 and q == 1
and r == 0 and last == 1):
return 1
if (p == 0 and q == 0 and
r == 1 and last == 2):
return 1
# if last ball required is P
# and the number of ways is
# the sum of number of ways
# to form sequence with 'p-1' P
# balls, q Q Balls and r R
# balls ending with Q and R.
if (last == 0):
return (countUtil(p - 1, q, r, 1) +
countUtil(p - 1, q, r, 2));
# Same as above case
# for 'q' and 'r'
if (last == 1):
return (countUtil(p, q - 1, r, 0) +
countUtil(p, q - 1, r, 2));
if (last == 2):
return (countUtil(p, q, r - 1, 0) +
countUtil(p, q, r - 1, 1));
def countWays(p, q, r):
# Three cases arise:
# Last required balls is type P
# Last required balls is type Q
# Last required balls is type R
return (countUtil(p, q, r, 0) +
countUtil(p, q, r, 1) +
countUtil(p, q, r, 2));
p = 1
q = 1
r = 1
res = countWays(p, q, r)
print(res)
// C# program to count number
// of ways to arrange three types of
// balls such that no two balls of
// same color are adjacent to each other
// uisng recursion
using System;
class GfG {
// Returns count of arrangements
// where last placed ball is
// 'last'. 'last' is 0 for 'p',
// 1 for 'q' and 2 for 'r'
static int countUtil(int p, int q, int r, int last) {
// if number of balls of any
// color becomes less than 0
// the number of ways
// arrangements is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// If last ball required is
// of type P and the number
// of balls of P type is 1
// while number of balls of
// other color is 0 the number
// of ways is 1.
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
// Same case as above for 'q' and 'r'
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// if last ball required is P
// and the number of ways is
// the sum of number of ways
// to form sequence with 'p-1' P
// balls, q Q Balls and r R balls
// ending with Q and R.
if (last == 0)
return countUtil(p - 1, q, r, 1)
+ countUtil(p - 1, q, r, 2);
// Same as above case for 'q' and 'r'
if (last == 1)
return countUtil(p, q - 1, r, 0)
+ countUtil(p, q - 1, r, 2);
if (last == 2)
return countUtil(p, q, r - 1, 0)
+ countUtil(p, q, r - 1, 1);
return 0;
}
// Returns count of required arrangements
static int countWays(int p, int q, int r) {
// Three cases arise:
// 1. Last required balls is type P
// 2. Last required balls is type Q
// 3. Last required balls is type R
return countUtil(p, q, r, 0) + countUtil(p, q, r, 1)
+ countUtil(p, q, r, 2);
}
static void Main() {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
Console.Write(res);
}
}
// JavaScript program to count number
// of ways to arrange three
// types of balls such that no
// two balls of same color
// are adjacent to each other
// using recursion
// Returns count of arrangements
// where last placed ball is
// 'last'. 'last' is 0 for 'p',
// 1 for 'q' and 2 for 'r'
function countUtil(p, q, r, last) {
// if number of balls of any
// color becomes less than 0
// the number of ways arrangements is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// If last ball required is
// of type P and the number
// of balls of P type is 1
// while number of balls of
// other color is 0 the number
// of ways is 1.
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
// Same case as above for 'q' and 'r'
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// if last ball required is P
// and the number of ways is
// the sum of number of ways
// to form sequence with 'p-1' P
// balls, q Q Balls and r R balls
// ending with Q and R.
if (last == 0)
return countUtil(p - 1, q, r, 1)
+ countUtil(p - 1, q, r, 2);
// Same as above case for 'q' and 'r'
if (last == 1)
return countUtil(p, q - 1, r, 0)
+ countUtil(p, q - 1, r, 2);
if (last == 2)
return countUtil(p, q, r - 1, 0)
+ countUtil(p, q, r - 1, 1);
return 0;
}
// Returns count of required arrangements
function countWays(p, q, r) {
return countUtil(p, q, r, 0) + countUtil(p, q, r, 1)
+ countUtil(p, q, r, 2);
}
let p = 1, q = 1, r = 1;
let res = countWays(p, q, r);
console.log(res);
Output
6
Using Top-Down DP (Memoization) - O(p*q*r) Time and O(p*q*r) Space
If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming.
1. Optimal Substructure:
The solution to the problem of arranging balls with no two adjacent balls of the same type can be derived from the optimal solutions of smaller subproblems.
2. Overlapping Subproblems:
In the recursive solution, we notice that many subproblems are solved multiple times. For example, when calculating countWays(p, q, r, last), the same values of p, q, r are computed multiple times.
- The recursive solution involves changing four parameters: the number of remaining balls of each type (p, q, r) and the last placed ball type (last). We need to track all these parameters, so we create a 4D array of size (p+1) x (q+1) x (r+1) x 3. This is because the values of p, q, and r will be in the range [0, p], [0, q], and [0, r], respectively, and the value of last will range from 0 to 2 (representing the three ball types: P, Q, and R).
- We initialize this 4D array with -1 to indicate that no subproblems have been computed yet.
- Before computing the number of arrangements for any subproblem, we check if the value at memo[p][q][r][last] is -1. If it is, we proceed to compute the result using the recursive relations. If it is, we proceed to compute the result. otherwise, we return the stored result.
// C++ program to count number of ways to arrange three
// types of balls such that no two balls of same color
// are adjacent to each other using tabulation
#include <iostream>
#include <vector>
using namespace std;
// Returns count of arrangements where last placed ball is
// 'last'. 'last' is 0 for 'p', 1 for 'q' and 2 for 'r'
int countUtil(int p, int q, int r, int last,
vector<vector<vector<vector<int>>>> &memo) {
// If number of balls of any color becomes less than 0,
// the number of ways to arrange them is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// Base cases: when only one ball is left, return 1 if
// the last ball is the right type
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// If this subproblem is already evaluated (memoized),
// return the stored result
if (memo[p][q][r][last] != -1)
return memo[p][q][r][last];
// Recursive calls to calculate number of arrangements
// based on the last ball
if (last == 0)
// If the last ball is P, the next ball can be Q or R
memo[p][q][r][last] = countUtil(p - 1, q, r, 1, memo)
+ countUtil(p - 1, q, r, 2, memo);
else if (last == 1)
// If the last ball is Q, the next ball can be P or R
memo[p][q][r][last] = countUtil(p, q - 1, r, 0, memo)
+ countUtil(p, q - 1, r, 2, memo);
else
// If the last ball is R, the next ball can be P or Q
memo[p][q][r][last] = countUtil(p, q, r - 1, 0, memo)
+ countUtil(p, q, r - 1, 1, memo);
return memo[p][q][r][last];
}
// Wrapper function to initialize memoization table
// and call countUtil
int countWays(int p, int q, int r) {
// Create a 4D vector for memoization with size
// (p+1) x (q+1) x (r+1) x 3
vector<vector<vector<vector<int>>>> memo(
p + 1,
vector<vector<vector<int>>>(
q + 1, vector<vector<int>>(
r + 1, vector<int>(3, -1))));
// Call countUtil for all possible last ball types (0, 1, 2)
int ans = countUtil(p, q, r, 0, memo) +
countUtil(p, q, r, 1, memo) + countUtil(p, q, r, 2, memo);
return ans;
}
int main() {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
cout << res << endl;
return 0;
}
// Java program to count number
// of ways to arrange three
// types of balls such that no
// two balls of same color
// are adjacent to each other
import java.util.*;
class GfG {
// Returns count of arrangements where last placed ball
// is 'last'. 'last' is 0 for 'p', 1 for 'q' and 2 for
// 'r'
static int
countUtil(int p, int q, int r, int last,
List<List<List<List<Integer> > > > memo) {
// If number of balls of any color becomes less than
// 0, the number of ways to arrange them is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// Base cases: when only one ball is left, return 1
// if the last ball is the right type
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// If this subproblem is already evaluated
// (memoized), return the stored result
if (memo.get(p).get(q).get(r).get(last) != -1)
return memo.get(p).get(q).get(r).get(last);
// Recursive calls to calculate number of
// arrangements based on the last ball
if (last == 0)
// If the last ball is P, the next ball can be Q
// or R
memo.get(p).get(q).get(r).set(
last,
countUtil(p - 1, q, r, 1, memo)
+ countUtil(p - 1, q, r, 2, memo));
else if (last == 1)
// If the last ball is Q, the next ball can be P
// or R
memo.get(p).get(q).get(r).set(
last,
countUtil(p, q - 1, r, 0, memo)
+ countUtil(p, q - 1, r, 2, memo));
else
// If the last ball is R, the next ball can be P
// or Q
memo.get(p).get(q).get(r).set(
last,
countUtil(p, q, r - 1, 0, memo)
+ countUtil(p, q, r - 1, 1, memo));
return memo.get(p).get(q).get(r).get(last);
}
// Wrapper function to initialize memoization table and
// call countUtil
static int countWays(int p, int q, int r) {
// Create a 4D list for memoization with size (p+1)
// x (q+1) x (r+1) x 3
List<List<List<List<Integer> > > > memo
= new ArrayList<>();
for (int i = 0; i <= p; i++) {
List<List<List<Integer> > > level2
= new ArrayList<>();
for (int j = 0; j <= q; j++) {
List<List<Integer> > level3
= new ArrayList<>();
for (int k = 0; k <= r; k++) {
List<Integer> level4 = new ArrayList<>(
Arrays.asList(-1, -1, -1));
level3.add(level4);
}
level2.add(level3);
}
memo.add(level2);
}
// Call countUtil for all possible last ball types
// (0, 1, 2)
int ans = countUtil(p, q, r, 0, memo)
+ countUtil(p, q, r, 1, memo)
+ countUtil(p, q, r, 2, memo);
return ans;
}
public static void main(String[] args) {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
System.out.print(res);
}
}
# Python program to count number of ways to arrange three
# types of balls such that no two balls of same color
# are adjacent to each other using tabulation
def countUtil(p, q, r, last, memo):
# If number of balls of any color becomes less than 0,
# the number of ways to arrange them is 0.
if p < 0 or q < 0 or r < 0:
return 0
# Base cases: when only one ball is left, return 1 if
# the last ball is the right type
if p == 1 and q == 0 and r == 0 and last == 0:
return 1
if p == 0 and q == 1 and r == 0 and last == 1:
return 1
if p == 0 and q == 0 and r == 1 and last == 2:
return 1
# If this subproblem is already evaluated
# (memoized), return the stored result
if memo[p][q][r][last] != -1:
return memo[p][q][r][last]
# Recursive calls to calculate number of
# arrangements based on the last ball
if last == 0:
# If the last ball is P, the next ball can be Q or R
memo[p][q][r][last] = countUtil(
p - 1, q, r, 1, memo) + countUtil(p - 1, q, r, 2, memo)
elif last == 1:
# If the last ball is Q, the next ball can be P or R
memo[p][q][r][last] = countUtil(
p, q - 1, r, 0, memo) + countUtil(p, q - 1, r, 2, memo)
else:
# If the last ball is R, the next ball can be P or Q
memo[p][q][r][last] = countUtil(
p, q, r - 1, 0, memo) + countUtil(p, q, r - 1, 1, memo)
return memo[p][q][r][last]
# Wrapper function to initialize memoization
# table and call countUtil
def countWays(p, q, r):
# Create a 4D list for memoization with size
# (p+1) x (q+1) x (r+1) x 3
memo = [[[[-1 for _ in range(3)] for _ in range(r + 1)]
for _ in range(q + 1)] for _ in range(p + 1)]
# Call countUtil for all possible last
# ball types (0, 1, 2)
ans = countUtil(p, q, r, 0, memo) + countUtil(p, q, r,
1, memo) + countUtil(p, q, r, 2, memo)
return ans
if __name__ == "__main__":
p = 1
q = 1
r = 1
res = countWays(p, q, r)
print(res)
// C# program to count number
// of ways to arrange three
// types of balls such that no
// two balls of same color
// are adjacent to each other
using System;
class GfG {
// Returns count of arrangements where last placed ball
// is 'last'. 'last' is 0 for 'p', 1 for 'q', and 2 for
// 'r'
static int countUtil(int p, int q, int r, int last,
int[, , , ] memo) {
// If number of balls of any color becomes less than
// 0, the number of ways to arrange them is 0.
if (p < 0 || q < 0 || r < 0)
return 0;
// Base cases: when only one ball of each type is
// left
if (p == 1 && q == 0 && r == 0 && last == 0)
return 1;
if (p == 0 && q == 1 && r == 0 && last == 1)
return 1;
if (p == 0 && q == 0 && r == 1 && last == 2)
return 1;
// If this subproblem is already evaluated
// (memoized), return the stored result
if (memo[p, q, r, last] != -1)
return memo[p, q, r, last];
// Recursive calls to calculate number of
// arrangements based on the last ball
if (last == 0) {
// If the last ball is P, the next ball can be Q
// or R
memo[p, q, r, last]
= countUtil(p - 1, q, r, 1, memo)
+ countUtil(p - 1, q, r, 2, memo);
}
else if (last == 1) {
// If the last ball is Q, the next ball can be P
// or R
memo[p, q, r, last]
= countUtil(p, q - 1, r, 0, memo)
+ countUtil(p, q - 1, r, 2, memo);
}
else {
// If the last ball is R, the next ball can be P
// or Q
memo[p, q, r, last]
= countUtil(p, q, r - 1, 0, memo)
+ countUtil(p, q, r - 1, 1, memo);
}
// Return the computed result and store it in the
// memoization table
return memo[p, q, r, last];
}
// Wrapper function to initialize memoization table and
// call countUtil
static int countWays(int p, int q, int r) {
// Create a 4D array for memoization with size (p+1)
// x (q+1) x (r+1) x 3
int[, , , ] memo = new int[p + 1, q + 1, r + 1, 3];
// Initialize all elements of the memo array to -1
for (int i = 0; i <= p; i++) {
for (int j = 0; j <= q; j++) {
for (int k = 0; k <= r; k++) {
for (int l = 0; l < 3; l++) {
memo[i, j, k, l] = -1;
}
}
}
}
// Call countUtil for all possible last ball types
// (0, 1, 2)
int ans = countUtil(p, q, r, 0, memo)
+ countUtil(p, q, r, 1, memo)
+ countUtil(p, q, r, 2, memo);
return ans;
}
static void Main() {
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
Console.WriteLine(res);
}
}
// JavaScript program to count number of ways to arrange
// three types of balls such that no two balls of same color
// are adjacent to each other using tabulation
// Returns count of arrangements where last placed ball is
// 'last'. 'last' is 0 for 'p', 1 for 'q' and 2 for 'r'
function countUtil(p, q, r, last, memo) {
// If number of balls of any color becomes less than 0,
// the number of ways to arrange them is 0.
if (p < 0 || q < 0 || r < 0) {
return 0;
}
// Base cases: when only one ball is left, return 1 if
// the last ball is the right type
if (p === 1 && q === 0 && r === 0 && last === 0) {
return 1;
}
if (p === 0 && q === 1 && r === 0 && last === 1) {
return 1;
}
if (p === 0 && q === 0 && r === 1 && last === 2) {
return 1;
}
// If this subproblem is already evaluated (memoized),
// return the stored result
if (memo[p][q][r][last] !== -1) {
return memo[p][q][r][last];
}
// Recursive calls to calculate number of arrangements
// based on the last ball
if (last === 0) {
// If the last ball is P, the next ball can be Q or
// R
memo[p][q][r][last]
= countUtil(p - 1, q, r, 1, memo)
+ countUtil(p - 1, q, r, 2, memo);
}
else if (last === 1) {
// If the last ball is Q, the next ball can be P or
// R
memo[p][q][r][last]
= countUtil(p, q - 1, r, 0, memo)
+ countUtil(p, q - 1, r, 2, memo);
}
else {
// If the last ball is R, the next ball can be P or
// Q
memo[p][q][r][last]
= countUtil(p, q, r - 1, 0, memo)
+ countUtil(p, q, r - 1, 1, memo);
}
return memo[p][q][r][last];
}
// Wrapper function to initialize memoization
// table and call countUtil
function countWays(p, q, r) {
// Create a 4D array for memoization with size (p+1) x
// (q+1) x (r+1) x 3
let memo = new Array(p + 1);
for (let i = 0; i <= p; i++) {
memo[i] = new Array(q + 1);
for (let j = 0; j <= q; j++) {
memo[i][j] = new Array(r + 1);
for (let k = 0; k <= r; k++) {
memo[i][j][k] = new Array(3).fill(
-1);
}
}
}
// Call countUtil for all possible last ball types (0,
// 1, 2)
let ans = countUtil(p, q, r, 0, memo)
+ countUtil(p, q, r, 1, memo)
+ countUtil(p, q, r, 2, memo);
return ans;
}
let p = 1, q = 1, r = 1;
let res = countWays(p, q, r);
console.log(res);
Output
6
Using Bottom-Up DP (Tabulation) – O(p*q*r) Time and O(p*q*r) Space
The approach is similar to the previous one. just instead of breaking down the problem recursively, we iteratively build up the solution by calculating in bottom-up manner.
So we will create 4D array of size (p+1)*(q+1)*(r+1)*last. and the state dp[i][j][k][l] will represent the number of ways to arrange the balls such that:
- i is the count of balls of type P placed so far.
- j is the count of balls of type Q placed so far.
- k is the count of balls of type R placed so far.
- l is the type of the last ball placed (l = 0 for P, l = 1 for Q, and l = 2 for R).
1. For the case where the last ball placed is of type P (i.e., l=0): if i>0, then dp[i][j][k][0] = dp[i-1][j][k][1] + dp[i-1][j][k][2]
2. For the case where the last ball placed is of type Q (i.e. ,l=1): if j>0, then dp[i][j][k][1]=dp[i][j-1][k][0]+dp[i][j-1][k][2]
3. For the case where the last ball placed is of type R (i.e., l=2): if k>0, then dp[i][j][k][2]=dp[i][j][k-1][0]+dp[i][j][k-1][1]
Base Cases
- dp[1][0][0][0]=1 (Only one P ball left, and the last placed ball is P)
- dp[0][1][0][1]=1 (Only one Q ball left, and the last placed ball is Q)
- dp[0][0][1][2]=1 (Only one R ball left, and the last placed ball is R)
// c++ program to count number of ways to arrange three
// types of balls such that no two balls of same color
// are adjacent to each other using tabulation
#include <bits/stdc++.h>
using namespace std;
// Function to count the number of arrangements
int countWays(int p, int q, int r) {
// Create a 4D DP table (p+1) x (q+1) x (r+1) x 3
vector<vector<vector<vector<int>>>> dp(
p + 1, vector<vector<vector<int>>>(q + 1,
vector<vector<int>>(r + 1, vector<int>(3, 0))));
// Base cases for when only one ball of each type is left
// Only p left and the last ball is p
dp[1][0][0][0] = 1;
// Only q left and the last ball is q
dp[0][1][0][1] = 1;
// Only r left and the last ball is r
dp[0][0][1][2] = 1;
// Iteratively fill the DP table
for (int pCount = 0; pCount <= p; pCount++) {
for (int qCount = 0; qCount <= q; qCount++) {
for (int rCount = 0; rCount <= r; rCount++) {
for (int last = 0; last < 3; last++) {
// If the count of balls is zero, skip
if (pCount == 0 && qCount == 0 && rCount == 0)
continue;
if (last == 0) {
// Last ball was P, so next can be Q or R
if (pCount > 0)
dp[pCount][qCount][rCount][last]
+= dp[pCount - 1][qCount][rCount][1];
if (pCount > 0)
dp[pCount][qCount][rCount][last]
+= dp[pCount - 1][qCount][rCount][2];
}
else if (last == 1) {
// Last ball was Q, so next can be P or R
if (qCount > 0) {
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount - 1][rCount][0];
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount - 1][rCount][2];
}
}
else {
// Last ball was R, so next can be P or Q
if (rCount > 0) {
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount][rCount - 1][0];
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount][rCount - 1][1];
}
}
}
}
}
}
// The answer is the sum of all configurations
// for the given p, q, r
int ans = dp[p][q][r][0]
+ dp[p][q][r][1] + dp[p][q][r][2];
return ans;
}
int main()
{
int p = 1, q = 1, r = 1;
int res = countWays(p, q, r);
cout << res << endl;
return 0;
}
// java program to count number of ways to arrange three
// types of balls such that no two balls of same color
// are adjacent to each other using tabulation
import java.util.*;
class GfG {
// Function to count the number of arrangements
// Function to count the number of arrangements
static int countWays(int p, int q, int r) {
// Create a 4D DP table (p+1) x (q+1) x (r+1) x 3
// using arrays
int[][][][] dp = new int[p + 1][q + 1][r + 1][3];
// Base cases for when only one ball of each type is
// left Only p left and the last ball is p
dp[1][0][0][0] = 1;
// Only q left and the last ball is q
dp[0][1][0][1] = 1;
// Only r left and the last ball is r
dp[0][0][1][2] = 1;
// Iteratively fill the DP table
for (int pCount = 0; pCount <= p; pCount++) {
for (int qCount = 0; qCount <= q; qCount++) {
for (int rCount = 0; rCount <= r;
rCount++) {
for (int last = 0; last < 3; last++) {
// If the count of balls is zero,
// skip
if (pCount == 0 && qCount == 0
&& rCount == 0)
continue;
if (last == 0) {
// Last ball was P, so next can
// be Q or R
if (pCount > 0)
dp[pCount][qCount][rCount]
[last]
+= dp[pCount - 1]
[qCount][rCount]
[1];
if (pCount > 0)
dp[pCount][qCount][rCount]
[last]
+= dp[pCount - 1]
[qCount][rCount]
[2];
}
else if (last == 1) {
// Last ball was Q, so next can
// be P or R
if (qCount > 0) {
dp[pCount][qCount][rCount]
[last]
+= dp[pCount]
[qCount - 1]
[rCount][0];
dp[pCount][qCount][rCount]
[last]
+= dp[pCount]
[qCount - 1]
[rCount][2];
}
}
else {
// Last ball was R, so next can
// be P or Q
if (rCount > 0) {
dp[pCount][qCount][rCount]
[last]
+= dp[pCount][qCount]
[rCount - 1][0];
dp[pCount][qCount][rCount]
[last]
+= dp[pCount][qCount]
[rCount - 1][1];
}
}
}
}
}
}
// The answer is the sum of all configurations for
// the given p, q, r
int ans = dp[p][q][r][0] + dp[p][q][r][1]
+ dp[p][q][r][2];
return ans;
}
public static void main(String[] args) {
int p = 1, q = 1, r = 1;
System.out.println(countWays(p, q, r));
}
}
# python program to count number of ways to arrange three
# types of balls such that no two balls of same color
# are adjacent to each other using tabulation
def countWays(p, q, r):
# Create a 4D DP table (p+1) x (q+1) x (r+1) x 3 using lists
dp = [[[[0 for _ in range(3)] for _ in range(r + 1)]
for _ in range(q + 1)] for _ in range(p + 1)]
# Base cases for when only one ball of each type is left
# Only p left and the last ball is p
dp[1][0][0][0] = 1
# Only q left and the last ball is q
dp[0][1][0][1] = 1
# Only r left and the last ball is r
dp[0][0][1][2] = 1
# Iteratively fill the DP table
for pCount in range(p + 1):
for qCount in range(q + 1):
for rCount in range(r + 1):
for last in range(3):
# If the count of balls is zero, skip
if pCount == 0 and qCount == 0 and rCount == 0:
continue
if last == 0:
# Last ball was P, so next can be Q or R
if pCount > 0:
dp[pCount][qCount][rCount][last] += dp[pCount -
1][qCount][rCount][1]
if pCount > 0:
dp[pCount][qCount][rCount][last] += dp[pCount -
1][qCount][rCount][2]
elif last == 1:
# Last ball was Q, so next can be P or R
if qCount > 0:
dp[pCount][qCount][rCount][last] += dp[pCount][qCount - 1][rCount][0]
dp[pCount][qCount][rCount][last] += dp[pCount][qCount - 1][rCount][2]
else:
# Last ball was R, so next can be P or Q
if rCount > 0:
dp[pCount][qCount][rCount][last] += dp[pCount][qCount][rCount - 1][0]
dp[pCount][qCount][rCount][last] += dp[pCount][qCount][rCount - 1][1]
# The answer is the sum of all configurations
# for the given p, q, r
ans = dp[p][q][r][0] + dp[p][q][r][1] + dp[p][q][r][2]
return ans
if __name__ == "__main__":
p, q, r = 1, 1, 1
print(countWays(p, q, r))
// c# program to count number of ways to arrange three
// types of balls such that no two balls of same color
// are adjacent to each other using tabulation
using System;
class GfG {
// Function to count the number of arrangements
static int countWays(int p, int q, int r) {
// Create a 4D DP table (p+1) x (q+1) x (r+1) x 3
// using arrays
int[, , , ] dp = new int[p + 1, q + 1, r + 1, 3];
// Base cases for when only one ball of each type is
// left Only p left and the last ball is p
dp[1, 0, 0, 0] = 1;
// Only q left and the last ball is q
dp[0, 1, 0, 1] = 1;
// Only r left and the last ball is r
dp[0, 0, 1, 2] = 1;
// Iteratively fill the DP table
for (int pCount = 0; pCount <= p; pCount++) {
for (int qCount = 0; qCount <= q; qCount++) {
for (int rCount = 0; rCount <= r;
rCount++) {
for (int last = 0; last < 3; last++) {
// If the count of balls is zero,
// skip
if (pCount == 0 && qCount == 0
&& rCount == 0)
continue;
if (last == 0) {
// Last ball was P, so next can
// be Q or R
if (pCount > 0)
dp[pCount, qCount, rCount,
last]
+= dp[pCount - 1,
qCount, rCount,
1];
if (pCount > 0)
dp[pCount, qCount, rCount,
last]
+= dp[pCount - 1,
qCount, rCount,
2];
}
else if (last == 1) {
// Last ball was Q, so next can
// be P or R
if (qCount > 0) {
dp[pCount, qCount, rCount,
last]
+= dp[pCount,
qCount - 1,
rCount, 0];
dp[pCount, qCount, rCount,
last]
+= dp[pCount,
qCount - 1,
rCount, 2];
}
}
else {
// Last ball was R, so next can
// be P or Q
if (rCount > 0) {
dp[pCount, qCount, rCount,
last]
+= dp[pCount, qCount,
rCount - 1, 0];
dp[pCount, qCount, rCount,
last]
+= dp[pCount, qCount,
rCount - 1, 1];
}
}
}
}
}
}
// The answer is the sum of all configurations for
// the given p, q, r
int ans = dp[p, q, r, 0] + dp[p, q, r, 1]
+ dp[p, q, r, 2];
return ans;
}
static void Main() {
int p = 1, q = 1, r = 1;
int ans = countWays(p, q, r);
Console.WriteLine(ans);
}
}
// JavaScript program to count number of ways to arrange
// three types of balls such that no two balls of same color
// are adjacent to each other using tabulation
function countWays(p, q, r) {
let dp = new Array(p + 1);
for (let i = 0; i <= p; i++) {
dp[i] = new Array(q + 1);
for (let j = 0; j <= q; j++) {
dp[i][j] = new Array(r + 1);
for (let k = 0; k <= r; k++) {
dp[i][j][k] = new Array(3).fill(0);
}
}
}
// Base cases for when only one ball of each type is
// left
dp[1][0][0][0] = 1;
dp[0][1][0][1] = 1;
dp[0][0][1][2] = 1;
// Iteratively fill the DP table
for (let pCount = 0; pCount <= p; pCount++) {
for (let qCount = 0; qCount <= q; qCount++) {
for (let rCount = 0; rCount <= r; rCount++) {
for (let last = 0; last < 3; last++) {
// If the count of balls is zero, skip
if (pCount === 0 && qCount === 0
&& rCount === 0)
continue;
if (last === 0) {
// Last ball was P, so next can be Q
// or R
if (pCount > 0)
dp[pCount][qCount][rCount][last]
+= dp[pCount
- 1][qCount][rCount][1];
if (pCount > 0)
dp[pCount][qCount][rCount][last]
+= dp[pCount
- 1][qCount][rCount][2];
}
else if (last === 1) {
// Last ball was Q, so next can be P
// or R
if (qCount > 0) {
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount
- 1][rCount][0];
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount
- 1][rCount][2];
}
}
else {
// Last ball was R, so next can be P
// or Q
if (rCount > 0) {
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount][rCount
- 1][0];
dp[pCount][qCount][rCount][last]
+= dp[pCount][qCount][rCount
- 1][1];
}
}
}
}
}
}
// The answer is the sum of all configurations for the
// given p, q, r
let ans
= dp[p][q][r][0] + dp[p][q][r][1] + dp[p][q][r][2];
return ans;
}
const p = 1, q = 1, r = 1;
let ans = countWays(p, q, r);
console.log(ans);
Output
6