Given a 2D array plates[][] of size N, which each row representing the length and width of a N rectangular plates, the task is to find the maximum number of plates that can be placed on one another.
Note: A plate can be put on another only if its length and width are strictly smaller than that plate.

Examples:
Input: Plates[][] = [ [3, 5], [6, 7], [7, 2], [2, 3] ]
Output: 3
Explanation: Plates can be arranged in this manner [ 6, 7 ] => [ 3, 5 ] => [ 2, 3 ].
Input: Plates[][] = [ [6, 4], [ 5, 7 ], [1, 2], [ 3, 3 ], [ 7, 9 ] ]
Output: 4
Explanation: Plates can be arranged in this manner [ 7, 9 ] => [ 5, 7 ] => [ 3, 3 ] => [ 1, 2 ].
Approach: The problem is a variation of the Longest increasing subsequence problem. The only difference is that in LIS, if i < j, then ith element will always come before the jth element. But here, choosing of plates doesn’t depend on index. So, to get this index restriction, sorting all the plates in decreasing order of area is required.
If (i < j) and area of ith plate is also greater than jth plate, then ith plate will always come before(down) the jth plate.
Two possible choices exists for each plate, i.e. either to include it in the sequence or discard it. A plate can be included only when its length and width are smaller than the previous included plate.
Recursion tree for the array plates[][] = [ [6, 7], [3, 5], [7, 2] ] is as follows:

Below is the implementation of the recursive approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool comp(vector< int > v1,
vector< int > v2)
{
return v1[0] * v1[1] > v2[0] * v2[1];
}
int countPlates(vector<vector< int > >& plates,
int lastLength, int lastWidth,
int i, int n)
{
if (i == n)
return 0;
int taken = 0, notTaken = 0;
if (lastLength > plates[i][0]
&& lastWidth > plates[i][1]) {
taken = 1 + countPlates(plates, plates[i][0],
plates[i][1], i + 1, n);
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
}
else
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
return max(taken, notTaken);
}
int main()
{
vector<vector< int > > plates = { { 6, 4 }, { 5, 7 },
{ 1, 2 }, { 3, 3 }, { 7, 9 } };
int n = plates.size();
sort(plates.begin(), plates.end(), comp);
int lastLength = INT_MAX;
int lastWidth = INT_MAX;
cout << countPlates(plates, lastLength,
lastWidth, 0, n);
return 0;
}
|
Java
import java.lang.*;
import java.util.*;
class GFG{
static int countPlates( int [][] plates,
int lastLength,
int lastWidth,
int i, int n)
{
if (i == n)
return 0 ;
int taken = 0 , notTaken = 0 ;
if (lastLength > plates[i][ 0 ] &&
lastWidth > plates[i][ 1 ])
{
taken = 1 + countPlates(plates, plates[i][ 0 ],
plates[i][ 1 ], i + 1 , n);
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1 , n);
}
else
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1 , n);
return Math.max(taken, notTaken);
}
public static void main(String[] args)
{
int [][] plates = { { 6 , 4 }, { 5 , 7 },
{ 1 , 2 }, { 3 , 3 }, { 7 , 9 } };
int n = plates.length;
Arrays.sort(plates, (v1, v2)-> (v2[ 0 ] * v2[ 1 ]) -
(v1[ 0 ] * v1[ 1 ]));
int lastLength = Integer.MAX_VALUE;
int lastWidth = Integer.MAX_VALUE;
System.out.println(countPlates(plates, lastLength,
lastWidth, 0 , n));
}
}
|
Python3
from functools import reduce
from operator import mul
def countPlates(plates, lastLength, lastWidth, i, n):
if i = = n:
return 0
taken = 0
not_taken = countPlates(plates, lastLength, lastWidth, i + 1 , n)
if lastLength > plates[i][ 0 ] and lastWidth > plates[i][ 1 ]:
taken = 1 + countPlates(plates, plates[i][ 0 ], plates[i][ 1 ], i + 1 , n)
else :
not_taken = countPlates(plates, lastLength, lastWidth, i + 1 , n)
return max (taken, not_taken)
plates = [( 6 , 4 ), ( 5 , 7 ), ( 1 , 2 ), ( 3 , 3 ), ( 7 , 9 )]
n = len (plates)
plates.sort(key = lambda tup: reduce (mul, tup), reverse = True )
lastlength = pow ( 10 , 9 )
lastwidth = pow ( 10 , 9 )
print (countPlates(plates, lastlength, lastwidth, 0 , n))
|
C#
using System;
using System.Linq;
class GFG {
static int countPlates( int [][] plates, int lastLength,
int lastWidth, int i, int n)
{
if (i == n)
return 0;
int taken = 0, notTaken = 0;
if (lastLength > plates[i][0]
&& lastWidth > plates[i][1]) {
taken = 1
+ countPlates(plates, plates[i][0],
plates[i][1], i + 1, n);
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
}
else
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
return Math.Max(taken, notTaken);
}
public static void Main( string [] args)
{
int [][] plates
= { new int [] { 6, 4 }, new int [] { 5, 7 },
new int [] { 1, 2 }, new int [] { 3, 3 },
new int [] { 7, 9 } };
int n = plates.Length;
Array.Sort(plates,
(v1, v2) => (v2[0] * v2[1]) - (v1[0] * v1[1]));
int lastLength = Int32.MaxValue;
int lastWidth = Int32.MaxValue;
Console.WriteLine(countPlates(plates, lastLength,
lastWidth, 0, n));
}
}
|
Javascript
<script>
function countPlates(plates, lastLength,
lastWidth, i, n)
{
if (i == n)
return 0;
var taken = 0, notTaken = 0;
if (lastLength > plates[i][0] &&
lastWidth > plates[i][1])
{
taken = 1 + countPlates(plates, plates[i][0],
plates[i][1], i + 1, n);
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
}
else
notTaken = countPlates(plates, lastLength,
lastWidth, i + 1, n);
return Math.max(taken, notTaken);
}
var plates = [ [ 6, 4 ], [ 5, 7 ],
[ 1, 2 ], [ 3, 3 ],
[ 7, 9 ] ];
var n = plates.length;
plates.sort((v1, v2) => v2[0] * v2[1] - v1[0] * v1[1]);
var lastLength = 1000000000;
var lastWidth = 1000000000;
document.write(countPlates(plates, lastLength,
lastWidth, 0, n));
</script>
|
Time Complexity: O(2N)
Auxiliary Space: O(N)
Dynamic Programming Approach: The above approach can be optimized using Dynamic programming as illustrated below.

Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool comp(vector< int > v1, vector< int > v2)
{
return v1[0] * v1[1] > v2[0] * v2[1];
}
int countPlates(vector<vector< int > >& plates, int n)
{
int maximum_plates = 1;
vector< int > dp(n, 1);
for ( int i = 1; i < n; i++) {
int cur = dp[i];
for ( int j = i - 1; j >= 0; j--) {
if (plates[i][0] < plates[j][0]
&& plates[i][1] < plates[j][1]) {
if (cur + dp[j] > dp[i]) {
dp[i] = cur + dp[j];
maximum_plates = max(maximum_plates, dp[i]);
}
}
}
}
return maximum_plates;
}
int main()
{
vector<vector< int > > plates = { { 6, 4 }, { 5, 7 },
{ 1, 2 }, { 3, 3 }, { 7, 9 } };
int n = plates.size();
sort(plates.begin(), plates.end(), comp);
cout << countPlates(plates, n);
return 0;
}
|
Java
import java.util.*;
import java.io.*;
class GFG{
static int countPlates(ArrayList<plate> plates, int n)
{
int maximum_plates = 1 ;
ArrayList<Integer> dp = new ArrayList<Integer>();
for ( int i = 1 ; i <= n ; i++){
dp.add( 1 );
}
for ( int i = 1 ; i < n; i++) {
int cur = dp.get(i);
for ( int j = i - 1 ; j >= 0 ; j--){
if (plates.get(i).l < plates.get(j).l && plates.get(i).b < plates.get(j).b) {
if (cur + dp.get(j) > dp.get(i)) {
dp.set(i, cur + dp.get(j));
maximum_plates = Math.max(maximum_plates, dp.get(i));
}
}
}
}
return maximum_plates;
}
public static void main(String args[])
{
ArrayList<plate> plates = new ArrayList<plate>(
List.of(
new plate( 6 , 4 ),
new plate( 5 , 7 ),
new plate( 1 , 2 ),
new plate( 3 , 3 ),
new plate( 7 , 9 )
)
);
int n = plates.size();
Collections.sort(plates, new comp());
System.out.println(countPlates(plates, n));
}
}
class plate{
int l, b;
plate( int l, int b){
this .l = l;
this .b = b;
}
}
class comp implements Comparator<plate>
{
public int compare(plate o1, plate o2){
int x1 = o1.l*o1.b;
int x2 = o2.l*o2.b;
return x2-x1;
}
}
|
Python3
C#
using System;
using System.Collections.Generic;
using System.Linq;
class GFG
{
static int countPlates(List<plate> plates, int n)
{
int maximum_plates = 1;
List< int > dp = new List< int >();
for ( int i = 1; i <= n; i++)
{
dp.Add(1);
}
for ( int i = 1; i < n; i++)
{
int cur = dp[i];
for ( int j = i - 1; j >= 0; j--)
{
if (plates[i].l < plates[j].l && plates[i].b < plates[j].b)
{
if (cur + dp[j] > dp[i])
{
dp[i] = cur + dp[j];
maximum_plates = Math.Max(maximum_plates, dp[i]);
}
}
}
}
return maximum_plates;
}
public static void Main( string [] args)
{
List<plate> plates = new List<plate>
{
new plate(6, 4),
new plate(5, 7),
new plate(1, 2),
new plate(3, 3),
new plate(7, 9)
};
int n = plates.Count();
plates = plates.OrderByDescending(x => x.l * x.b).ToList();
Console.WriteLine(countPlates(plates, n));
}
}
class plate
{
public int l, b;
public plate( int l, int b)
{
this .l = l;
this .b = b;
}
}
|
Javascript
<script>
function countPlates(plates, n)
{
var maximum_plates = 1;
var dp = Array(n).fill(1);
for ( var i = 1; i < n; i++)
{
var cur = dp[i];
for ( var j = i - 1; j >= 0; j--)
{
if (plates[i][0] < plates[j][0] &&
plates[i][1] < plates[j][1])
{
if (cur + dp[j] > dp[i])
{
dp[i] = cur + dp[j];
maximum_plates = Math.max(
maximum_plates, dp[i]);
}
}
}
}
return maximum_plates;
}
var plates = [ [ 6, 4 ], [ 5, 7 ],
[ 1, 2 ], [ 3, 3 ],
[ 7, 9 ] ];
var n = plates.length;
plates.sort((v1, v2) => {
return ((v2[0] * v2[1]) - (v1[0] * v1[1]));
});
document.write(countPlates(plates, n));
</script>
|
Time Complexity: O(N2)
Auxiliary Space: O(N)