Given 4 numbers N, M, X, Y. which represent N numbers for the first item and M numbers for the second item, the task is to find the number of arrangements of N + M items together such that not more than X first items and not more than Y second items are placed successively.
Examples:
Input: N = 2, M = 1, X = 1, Y = 10
Output: 1
Explanation: Let’s mark the first item as 1
and the second item as 2 the only arrangement possible is 121.Input: N = 2, M = 3, X = 1, Y = 2
Output: 5
Explanation: Lets mark the first element as 1 and second element as 2.
The arrangements possible are 12122, 12212, 21212, 21221, 22121.
Approach: To solve the problem follow the below observations and steps:
There are many possibilities of placing up to X first items and then up to Y second items. So to check each and every possibility we can use dynamic programming.
Since at each step N, M, X, and Y will change so there will be 4 states of dp[] array.
Let the f(n, m, x, y) represents number of ways to choose to make a valid arrangement with x consecutive 1st type elements and y consecutive elements.
So there can be 2 cases: We place first type element: f(n-1, m, x-1, y) or
we choose second type of element: f(n, m-1, x, y-1)So f(n, m, x, y) = f(n – 1, m, x – 1, y) + f(n, m – 1, x, y – 1)
Here is the case that if m or n becomes 0 then on the next iteration we cannot use another consecutive element if 1st or 2nd type.
Follow the below steps to implement the approach:
- Create a recursive function and a 4dimensional array (say dp[]) that will store each of the states.
- Recursively call the functions as mentioned above maintaining the mentioned edge case.
- Return the final value stored at dp[N][M][X][Y] as the required answer.
Below is the implementation of the above approach:
// C++ code to implement the approach. #include <bits/stdc++.h> using namespace std;
// dp array int dp[101][101][11][11];
// To store original value of X, Y int limit_f = 0, limit_s = 0;
// Function to find number of ways int numofways( int n, int m, int x, int y)
{ // Base case if n1+n2 is 0 that all
// items are placed then 1 arrangement
// is complete
if (n + m == 0)
return 1;
int f = 0, s = 0;
if (dp[n][m][x][y] != -1)
// The value is precomputed or not
return dp[n][m][x][y];
// If 1st item can be placed
if (n > 0 && x > 0)
// Since we place the first item
// there are limit_s second items
// can be placed consecutively
f = numofways(n - 1, m, x - 1, limit_s);
if (m > 0 && y > 0)
// Since we place the second item there
// are limit_f first item can be
// placed consecutively
s = numofways(n, m - 1, limit_f, y - 1);
// Total number of arrangements is
// addition of 2
return dp[n][m][x][y] = (f + s);
} // Driver code int main()
{ int N = 2, M = 3, X = 1, Y = 2;
limit_f = X, limit_s = Y;
// Initialization
for ( int i = 0; i <= N; i++) {
for ( int j = 0; j <= M; j++) {
for ( int k = 0; k <= X; k++) {
for ( int m = 0; m <= Y; m++)
dp[i][j][k][m] = -1;
}
}
}
// Function call
cout << numofways(N, M, X, Y) << endl;
return 0;
} |
// Java code to implement the approach. import java.io.*;
class GFG
{ // dp array
static int dp[][][][] = new int [ 101 ][ 101 ][ 11 ][ 11 ];
// To store original value of X, Y
static int limit_f = 0 , limit_s = 0 ;
// Function to find number of ways
public static int numofways( int n, int m, int x, int y)
{
// Base case if n1+n2 is 0 that all
// items are placed then 1 arrangement
// is complete
if (n + m == 0 )
return 1 ;
int f = 0 , s = 0 ;
if (dp[n][m][x][y] != - 1 )
// The value is precomputed or not
return dp[n][m][x][y];
// If 1st item can be placed
if (n > 0 && x > 0 )
// Since we place the first item
// there are limit_s second items
// can be placed consecutively
f = numofways(n - 1 , m, x - 1 , limit_s);
if (m > 0 && y > 0 )
// Since we place the second item there
// are limit_f first item can be
// placed consecutively
s = numofways(n, m - 1 , limit_f, y - 1 );
// Total number of arrangements is
// addition of 2
return dp[n][m][x][y] = (f + s);
}
// Driver Code
public static void main(String[] args)
{
int N = 2 , M = 3 , X = 1 , Y = 2 ;
limit_f = X;
limit_s = Y;
// Initialization
for ( int i = 0 ; i <= N; i++) {
for ( int j = 0 ; j <= M; j++) {
for ( int k = 0 ; k <= X; k++) {
for ( int m = 0 ; m <= Y; m++)
dp[i][j][k][m] = - 1 ;
}
}
}
// Function call
System.out.println(numofways(N, M, X, Y));
}
} // This code is contributed by Rohit Pradhan |
# dp array dp = [ - 1 ] * 101 ;
for i in range ( 0 , len (dp)):
dp[i] = [ - 1 ] * 101
for j in range ( 0 , len (dp[i])):
dp[i][j] = [ - 1 ] * 11
for k in range ( 0 , len (dp[i][j])):
dp[i][j][k] = [ - 1 ] * 11
# To store original value of X, Y limit_f = 0
limit_s = 0
# Function to find number of ways def numofways(n, m, x, y):
# Base case if n1+n2 is 0 that all
# items are placed then 1 arrangement
# is complete
if (n + m is 0 ):
return 1
f = 0
s = 0
if (dp[n][m][x][y] ! = - 1 ):
# The value is precomputed or not
return dp[n][m][x][y]
# If 1st item can be placed
if (n > 0 and x > 0 ):
# Since we place the first item
# there are limit_s second items
# can be placed consecutively
f = numofways(n - 1 , m, x - 1 , limit_s)
if (m > 0 and y > 0 ):
# Since we place the second item there
# are limit_f first item can be
# placed consecutively
s = numofways(n, m - 1 , limit_f, y - 1 )
# Total number of arrangements is
# addition of 2
dp[n][m][x][y] = (f + s)
return dp[n][m][x][y]
# Driver code N = 2
M = 3
X = 1
Y = 2
limit_f = X
limit_s = Y
# Initialization for i in range ( 0 ,N + 1 ):
for j in range ( 0 ,M + 1 ):
for k in range ( 0 ,X + 1 ):
for m in range ( 0 ,Y + 1 ):
dp[i][j][k][m] = - 1
# Function call print (numofways(N, M, X, Y))
# This code is contributed by akashish__ |
// C# code to implement the approach using System;
public class GFG
{ // dp array
public static int [,,,] dp = new int [101,101,11,11];
// To store original value of X, Y
public static int limit_f = 0;
public static int limit_s = 0;
// Function to find number of ways
public static int numofways( int n, int m, int x, int y)
{
// Base case if n1+n2 is 0 that all
// items are placed then 1 arrangement
// is complete
if (n + m == 0)
return 1;
int f = 0, s = 0;
if (dp[n,m,x,y] != -1)
// The value is precomputed or not
return dp[n,m,x,y];
// If 1st item can be placed
if (n > 0 && x > 0)
// Since we place the first item
// there are limit_s second items
// can be placed consecutively
f = numofways(n - 1, m, x - 1, limit_s);
if (m > 0 && y > 0)
// Since we place the second item there
// are limit_f first item can be
// placed consecutively
s = numofways(n, m - 1, limit_f, y - 1);
// Total number of arrangements is
// addition of 2
return dp[n,m,x,y] = (f + s);
}
public static void Main( string [] args)
{
int N = 2, M = 3, X = 1, Y = 2;
limit_f = X; limit_s = Y;
// Initialization
for ( int i = 0; i <= N; i++) {
for ( int j = 0; j <= M; j++) {
for ( int k = 0; k <= X; k++) {
for ( int m = 0; m <= Y; m++)
dp[i,j,k,m] = -1;
}
}
}
// Function call
Console.WriteLine(numofways(N, M, X, Y));
}
} // This code is contributed by ksam24000 |
<script> // JavaScript code for the above approach
let dp = new Array(101);
for (let i = 0; i < dp.length; i++) {
dp[i] = new Array(101);
for (let j = 0; j < dp[i].length; j++) {
dp[i][j] = new Array(11);
for (let k = 0; k < dp[i][j].length; k++) {
dp[i][j][k] = new Array(11);
}
}
}
// To store original value of X, Y
let limit_f = 0, limit_s = 0;
// Function to find number of ways
function numofways(n, m, x, y)
{
// Base case if n1+n2 is 0 that all
// items are placed then 1 arrangement
// is complete
if (n + m == 0)
return 1;
let f = 0, s = 0;
if (dp[n][m][x][y] != -1)
// The value is precomputed or not
return dp[n][m][x][y];
// If 1st item can be placed
if (n > 0 && x > 0)
// Since we place the first item
// there are limit_s second items
// can be placed consecutively
f = numofways(n - 1, m, x - 1, limit_s);
if (m > 0 && y > 0)
// Since we place the second item there
// are limit_f first item can be
// placed consecutively
s = numofways(n, m - 1, limit_f, y - 1);
// Total number of arrangements is
// addition of 2
return dp[n][m][x][y] = (f + s);
}
// Driver code
let N = 2, M = 3, X = 1, Y = 2;
limit_f = X, limit_s = Y;
// Initialization
for (let i = 0; i <= N; i++) {
for (let j = 0; j <= M; j++) {
for (let k = 0; k <= X; k++) {
for (let m = 0; m <= Y; m++)
dp[i][j][k][m] = -1;
}
}
}
// Function call
document.write(numofways(N, M, X, Y));
// This code is contributed by Potta Lokesh </script>
|
5
Time Complexity: O(N * M * X * Y)
Auxiliary Space: O(N * M * X * Y),
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Below is the implentation of the above approach:
// C++ code to implement the approach. #include <bits/stdc++.h> using namespace std;
// Function to find number of ways int numofways( int n, int m, int x, int y)
{ // dp array
int dp[n + 1][m + 1][x + 1][y + 1];
// initialize dp with base cases
memset (dp, 0, sizeof (dp));
// Base case initialization
for ( int i = 0; i <= n; i++) {
for ( int j = 0; j <= m; j++) {
for ( int k = 0; k <= x; k++) {
for ( int l = 0; l <= y; l++) {
if (i + j == 0)
dp[i][j][k][l] = 1;
}
}
}
}
// iterate over subproblems and get the current
// solution for previous computations
for ( int i = 0; i <= n; i++) {
for ( int j = 0; j <= m; j++) {
for ( int k = 0; k <= x; k++) {
for ( int l = 0; l <= y; l++) {
if (dp[i][j][k][l] == 0) {
int f = 0, s = 0;
if (i > 0 && k > 0)
f = dp[i - 1][j][k - 1][y];
if (j > 0 && l > 0)
s = dp[i][j - 1][x][l - 1];
dp[i][j][k][l] = f + s;
}
}
}
}
}
// return answer
return dp[n][m][x][y];
} // Driver code int main()
{ int N = 2, M = 3, X = 1, Y = 2;
// Function call
cout << numofways(N, M, X, Y) << endl;
return 0;
} |
// Java Implementation: import java.util.Arrays;
public class Main {
// Function to find number of ways
public static int numofways( int n, int m, int x, int y) {
// dp array
int [][][][] dp = new int [n + 1 ][m + 1 ][x + 1 ][y + 1 ];
// initialize dp with base cases
for ( int [][][] arr1 : dp) {
for ( int [][] arr2 : arr1) {
for ( int [] arr3 : arr2) {
Arrays.fill(arr3, 0 );
}
}
}
// Base case initialization
for ( int i = 0 ; i <= n; i++) {
for ( int j = 0 ; j <= m; j++) {
for ( int k = 0 ; k <= x; k++) {
for ( int l = 0 ; l <= y; l++) {
if (i + j == 0 )
dp[i][j][k][l] = 1 ;
}
}
}
}
// iterate over subproblems and get the current
// solution for previous computations
for ( int i = 0 ; i <= n; i++) {
for ( int j = 0 ; j <= m; j++) {
for ( int k = 0 ; k <= x; k++) {
for ( int l = 0 ; l <= y; l++) {
if (dp[i][j][k][l] == 0 ) {
int f = 0 , s = 0 ;
if (i > 0 && k > 0 )
f = dp[i - 1 ][j][k - 1 ][y];
if (j > 0 && l > 0 )
s = dp[i][j - 1 ][x][l - 1 ];
dp[i][j][k][l] = f + s;
}
}
}
}
}
// return answer
return dp[n][m][x][y];
}
// Driver code
public static void main(String[] args) {
int N = 2 , M = 3 , X = 1 , Y = 2 ;
// Function call
System.out.println(numofways(N, M, X, Y));
}
} // This code is contributed by Sakshi |
def num_of_ways(n, m, x, y):
# Initialize dp array with zeros
dp = [[[[ 0 for _ in range (y + 1 )] for _ in range (x + 1 )] for _ in range (m + 1 )] for _ in range (n + 1 )]
# Base case initialization
for i in range (n + 1 ):
for j in range (m + 1 ):
for k in range (x + 1 ):
for l in range (y + 1 ):
if i + j = = 0 :
dp[i][j][k][l] = 1
# Iterate over subproblems and compute the current solution based on previous computations
for i in range (n + 1 ):
for j in range (m + 1 ):
for k in range (x + 1 ):
for l in range (y + 1 ):
if dp[i][j][k][l] = = 0 :
f, s = 0 , 0
if i > 0 and k > 0 :
f = dp[i - 1 ][j][k - 1 ][y]
if j > 0 and l > 0 :
s = dp[i][j - 1 ][x][l - 1 ]
dp[i][j][k][l] = f + s
# Return the answer
return dp[n][m][x][y]
# Driver code if __name__ = = "__main__" :
N, M, X, Y = 2 , 3 , 1 , 2
# Function call
print (num_of_ways(N, M, X, Y))
|
using System;
class Program
{ // Function to find the number of ways
static int NumOfWays( int n, int m, int x, int y)
{
// 4D dp array
int [,,,] dp = new int [n + 1, m + 1, x + 1, y + 1];
// Initialize dp with base cases
for ( int i = 0; i <= n; i++)
{
for ( int j = 0; j <= m; j++)
{
for ( int k = 0; k <= x; k++)
{
for ( int l = 0; l <= y; l++)
{
if (i + j == 0)
dp[i, j, k, l] = 1;
}
}
}
}
// Iterate over subproblems and get the current solution for previous computations
for ( int i = 0; i <= n; i++)
{
for ( int j = 0; j <= m; j++)
{
for ( int k = 0; k <= x; k++)
{
for ( int l = 0; l <= y; l++)
{
if (dp[i, j, k, l] == 0)
{
int f = 0, s = 0;
if (i > 0 && k > 0)
f = dp[i - 1, j, k - 1, y];
if (j > 0 && l > 0)
s = dp[i, j - 1, x, l - 1];
dp[i, j, k, l] = f + s;
}
}
}
}
}
// Return the answer
return dp[n, m, x, y];
}
static void Main()
{
int N = 2, M = 3, X = 1, Y = 2;
// Function call
Console.WriteLine(NumOfWays(N, M, X, Y));
}
} |
// Function to find the number of ways function numOfWays(n, m, x, y) {
// 4D dp array
let dp = new Array(n + 1);
// Initialize the 4D dp array
for (let i = 0; i <= n; i++) {
dp[i] = new Array(m + 1);
for (let j = 0; j <= m; j++) {
dp[i][j] = new Array(x + 1);
for (let k = 0; k <= x; k++) {
dp[i][j][k] = new Array(y + 1).fill(0);
}
}
}
// Initialize dp with base cases
for (let i = 0; i <= n; i++) {
for (let j = 0; j <= m; j++) {
for (let k = 0; k <= x; k++) {
for (let l = 0; l <= y; l++) {
// Base case: when both n and m are 0
if (i + j === 0) {
dp[i][j][k][l] = 1;
}
}
}
}
}
// Iterate over subproblems and get the current solution for previous computations
for (let i = 0; i <= n; i++) {
for (let j = 0; j <= m; j++) {
for (let k = 0; k <= x; k++) {
for (let l = 0; l <= y; l++) {
// If the current solution is not calculated yet
if (dp[i][j][k][l] === 0) {
let f = 0,
s = 0;
// Recursively calculate the solutions for the subproblems
if (i > 0 && k > 0) {
f = dp[i - 1][j][k - 1][y];
}
if (j > 0 && l > 0) {
s = dp[i][j - 1][x][l - 1];
}
// Update the current solution
dp[i][j][k][l] = f + s;
}
}
}
}
}
// Return the answer
return dp[n][m][x][y];
} // Function call const N = 2, M = 3, X = 1, Y = 2; console.log(numOfWays(N, M, X, Y)); |
5
Time Complexity: O(N * M * X * Y)
Auxiliary Space: O(N * M * X * Y),