Given height and width of N rectangles. The task is to find the size of the largest subset such that no pair of rectangles fit within each other. Note that if H1 ? H2 and W1 ? W2 then rectangle 1 fits inside rectangle 2.
Examples:
Input: arr[] = {{1, 3}, {2, 2}, {1, 3}}
Output: 2
The required sub-set is {{1, 3}, {2, 2}}
{1, 3} is included only once as it can fit in {1, 3}Input: arr[] = {{1, 5}, {2, 4}, {1, 1}, {3, 3}}
Output: 3
Approach: The above problem can be solved using Dynamic Programming and sorting. Initially, we can sort the N pairs on the basis of heights. A recursive function can be written where there will be two states.
The first state being, if the present rectangle does not fit in the previous rectangle or the vice versa, then we call for the next state with the present rectangle being the previous rectangle and moving to the next rectangle.
dp[present][previous] = max(dp[present][previous], 1 + dp[present + 1][present])
If it does fit in, we call the next state with the previous rectangle and moving to the next rectangle.
dp[present][previous] = max(dp[present][previous], dp[present + 1][previous])
Memoization can be further used to avoid repetitively the same states being called.
Below is the implementation of the above approach:
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std;
#define N 10 int dp[N][N];
// Recursive function to get the largest subset int findLongest(pair< int , int > a[], int n,
int present, int previous)
{ // Base case when it exceeds
if (present == n) {
return 0;
}
// If the state has been visited previously
else if (previous != -1) {
if (dp[present][previous] != -1)
return dp[present][previous];
}
// Initialize
int ans = 0;
// No elements in subset yet
if (previous == -1) {
// First state which includes current index
ans = 1 + findLongest(a, n,
present + 1, present);
// Second state which does not include current index
ans = max(ans, findLongest(a, n,
present + 1, previous));
}
else {
int h1 = a[previous].first;
int h2 = a[present].first;
int w1 = a[previous].second;
int w2 = a[present].second;
// If the rectangle fits in, then do not include
// the current index in subset
if ((h1 <= h2 && w1 <= w2)) {
ans = max(ans, findLongest(a, n,
present + 1, previous));
}
else {
// First state which includes current index
ans = 1 + findLongest(a, n,
present + 1, present);
// Second state which does not include current index
ans = max(ans, findLongest(a, n,
present + 1, previous));
}
}
return dp[present][previous] = ans;
} // Function to get the largest subset int getLongest(pair< int , int > a[], int n)
{ // Initialize the DP table with -1
memset (dp, -1, sizeof dp);
// Sort the array
sort(a, a + n);
// Get the answer
int ans = findLongest(a, n, 0, -1);
return ans;
} // Driver code int main()
{ // (height, width) pairs
pair< int , int > a[] = { { 1, 5 },
{ 2, 4 },
{ 1, 1 },
{ 3, 3 } };
int n = sizeof (a) / sizeof (a[0]);
cout << getLongest(a, n);
return 0;
} |
// Java implementation of the above approach. import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
public class GFG {
// A function to sort the 2D array by column number.
static void Sort( int [][] array, final int columnNumber)
{
Arrays.sort(array, new Comparator< int []>() {
@Override
public int compare( int [] first, int [] second)
{
if (columnNumber >= 1
&& first[columnNumber - 1 ]
> second[columnNumber - 1 ])
return 1 ;
else
return - 1 ;
}
});
}
// Recursive function to get the largest subset
static int findLongest( int [][] a, int n, int present,
int previous, int [][] dp, int N)
{
// Base case when it exceeds
if (present == n) {
return 0 ;
}
// If the state has been visited previously
else if (previous != - 1 ) {
if (dp[present][previous] != - 1 )
return dp[present][previous];
}
// Initialize
int ans = 0 ;
// No elements in subset yet
if (previous == - 1 ) {
// First state which includes current index
ans = 1
+ findLongest(a, n, present + 1 , present,
dp, N);
// Second state which does not include current
// index
ans = Math.max(ans,
findLongest(a, n, present + 1 ,
previous, dp, N));
}
else {
int h1 = a[previous][ 0 ];
int h2 = a[present][ 0 ];
int w1 = a[previous][ 1 ];
int w2 = a[present][ 1 ];
// If the rectangle fits in, then do not include
// the current index in subset
if ((h1 <= h2 && w1 <= w2)) {
ans = Math.max(
ans, findLongest(a, n, present + 1 ,
previous, dp, N));
}
else {
// First state which includes current index
ans = 1
+ findLongest(a, n, present + 1 ,
present, dp, N);
// Second state which does not include
// current index
ans = Math.max(
ans, findLongest(a, n, present + 1 ,
previous, dp, N));
}
}
if (present >= 0 && previous >= 0 ) {
return dp[present][previous] = ans;
}
return ans;
}
// Function to get the largest subset
static int getLongest( int [][] a, int n)
{
int N = 10 ;
int [][] dp = new int [N + 1 ][N + 1 ];
// Initialize the DP table with -1
for ( int i = 0 ; i < N + 1 ; i++) {
for ( int j = 0 ; j < N + 1 ; j++) {
dp[i][j] = - 1 ;
}
}
// Sort the array
Sort(a, 0 );
// Get the answer
int ans = findLongest(a, n, 0 , - 1 , dp, N);
return ans;
}
// Driver code
// (height, width) pairs
public static void main(String[] args)
{
int [][] a
= { { 1 , 5 }, { 2 , 4 }, { 1 , 1 }, { 3 , 3 } };
int n = a.length;
System.out.println(getLongest(a, n));
}
} // The code is contributed by Gautam goel (guatamgoel962)
|
# Python3 implementation of the approach # Recursive function to get the # largest subset def findLongest(a, n, present, previous):
# Base case when it exceeds
if present = = n:
return 0
# If the state has been visited
# previously
elif previous ! = - 1 :
if dp[present][previous] ! = - 1 :
return dp[present][previous]
# Initialize
ans = 0
# No elements in subset yet
if previous = = - 1 :
# First state which includes
# current index
ans = 1 + findLongest(a, n, present + 1 ,
present)
# Second state which does not
# include current index
ans = max (ans, findLongest(a, n, present + 1 ,
previous))
else :
h1 = a[previous][ 0 ]
h2 = a[present][ 0 ]
w1 = a[previous][ 1 ]
w2 = a[present][ 1 ]
# If the rectangle fits in, then do
# not include the current index in subset
if h1 < = h2 and w1 < = w2:
ans = max (ans, findLongest(a, n, present + 1 ,
previous))
else :
# First state which includes
# current index
ans = 1 + findLongest(a, n, present + 1 ,
present)
# Second state which does not
# include current index
ans = max (ans, findLongest(a, n, present + 1 ,
previous))
dp[present][previous] = ans
return ans
# Function to get the largest subset def getLongest(a, n):
# Sort the array
a.sort()
# Get the answer
ans = findLongest(a, n, 0 , - 1 )
return ans
# Driver code if __name__ = = "__main__" :
# (height, width) pairs
a = [[ 1 , 5 ], [ 2 , 4 ], [ 1 , 1 ], [ 3 , 3 ]]
N = 10
# Initialize the DP table with -1
dp = [[ - 1 for i in range (N)]
for j in range (N)]
n = len (a)
print (getLongest(a, n))
# This code is contributed # by Rituraj Jain |
using System;
using System.Linq;
class GFG {
// A function to sort the 2D array by column number.
static void Sort( int [][] array, int columnNumber)
{
Array.Sort(array, (first, second) = > {
if (columnNumber >= 1
&& first[columnNumber - 1]
> second[columnNumber - 1]) {
return 1;
}
else {
return -1;
}
});
}
// Recursive function to get the largest subset
static int findLongest( int [][] a, int n, int present,
int previous, int [][] dp, int N)
{
// Base case when it exceeds
if (present == n) {
return 0;
}
// If the state has been visited previously
else if (previous != -1) {
if (dp[present][previous] != -1)
return dp[present][previous];
}
// Initialize
int ans = 0;
// No elements in subset yet
if (previous == -1) {
// First state which includes current index
ans = 1
+ findLongest(a, n, present + 1, present,
dp, N);
// Second state which does not include current
// index
ans = Math.Max(ans,
findLongest(a, n, present + 1,
previous, dp, N));
}
else {
int h1 = a[previous][0];
int h2 = a[present][0];
int w1 = a[previous][1];
int w2 = a[present][1];
// If the rectangle fits in, then do not include
// the current index in subset
if ((h1 <= h2 && w1 <= w2)) {
ans = Math.Max(
ans, findLongest(a, n, present + 1,
previous, dp, N));
}
else {
// First state which includes current index
ans = 1
+ findLongest(a, n, present + 1,
present, dp, N);
// Second state which does not include
// current index
ans = Math.Max(
ans, findLongest(a, n, present + 1,
previous, dp, N));
}
}
if (present >= 0 && previous >= 0) {
return dp[present][previous] = ans;
}
return ans;
}
// Function to get the largest subset
static int getLongest( int [][] a, int n)
{
int N = 10;
int [][] dp = new int [N + 1][];
for ( int i = 0; i <= N; i++)
dp[i] = Enumerable.Repeat(-1, N + 1).ToArray();
// Sort the array
Sort(a, 0);
// Get the answer
int ans = findLongest(a, n, 0, -1, dp, N);
return ans;
}
// Driver code
// (height, width) pairs
public static void Main( string [] args)
{
int [][] a = new int [4][];
a[0] = new int [] { 1, 5 };
a[1] = new int [] { 2, 4 };
a[2] = new int [] { 1, 1 };
a[3] = new int [] { 3, 3 };
int n = a.Length;
Console.WriteLine(getLongest(a, n));
}
} |
<script> // JavaScript implementation of the approach var N = 10;
var dp = Array.from(Array(N), ()=>Array(N).fill(-1));
// Recursive function to get the largest subset function findLongest(a, n, present, previous)
{ // Base case when it exceeds
if (present == n) {
return 0;
}
// If the state has been visited previously
else if (previous != -1) {
if (dp[present][previous] != -1)
return dp[present][previous];
}
// Initialize
var ans = 0;
// No elements in subset yet
if (previous == -1) {
// First state which includes current index
ans = 1 + findLongest(a, n,
present + 1, present);
// Second state which does not include current index
ans = Math.max(ans, findLongest(a, n,
present + 1, previous));
}
else {
var h1 = a[previous][0];
var h2 = a[present][0];
var w1 = a[previous][1];
var w2 = a[present][1];
// If the rectangle fits in, then do not include
// the current index in subset
if ((h1 <= h2 && w1 <= w2)) {
ans = Math.max(ans, findLongest(a, n,
present + 1, previous));
}
else {
// First state which includes current index
ans = 1 + findLongest(a, n,
present + 1, present);
// Second state which does not include current index
ans = Math.max(ans, findLongest(a, n,
present + 1, previous));
}
}
return dp[present][previous] = ans;
} // Function to get the largest subset function getLongest(a, n)
{ // Initialize the DP table with -1
dp = Array.from(Array(N), ()=>Array(N).fill(-1));
// Sort the array
a.sort((a,b)=>a-b);
// Get the answer
var ans = findLongest(a, n, 0, -1);
return ans;
} // Driver code // (height, width) pairs var a = [ [ 1, 5 ],
[ 2, 4 ],
[ 1, 1 ],
[ 3, 3 ] ];
var n = a.length;
document.write( getLongest(a, n)); </script> |
3
Time Complexity: O(N*N), where dp operations taking N*N time
Auxiliary Space: O(N*N), dp array made of two states each having N space, i.e. N*N
New approach:- Another approach to solve this problem is by using greedy algorithm. We can sort the rectangles in decreasing order of their widths, so that the widest rectangle is considered first. Then, we can add the widest rectangle to the subset and remove all the rectangles that it can contain from the remaining set of rectangles. We can repeat this process with the remaining set of rectangles until we can’t find any more rectangles that fit in the current subset.
Here’s the implementation of the above approach:
#include <iostream> #include <vector> #include <algorithm> using namespace std;
int getLongest(vector<pair< int , int >>& arr) {
// sort the rectangles in decreasing order of their widths
sort(arr.begin(), arr.end(), []( const pair< int , int >& a, const pair< int , int >& b) {
return a.second > b.second;
});
// initialize the subset with the widest rectangle
vector<pair< int , int >> subset = {arr[0]};
// iterate over the remaining rectangles
for ( int i = 1; i < arr.size(); i++) {
// check if the current rectangle can fit in any rectangle in the subset
bool fits = false ;
for ( const auto & rect : subset) {
if (arr[i].first <= rect.first && arr[i].second <= rect.second) {
fits = true ;
break ;
}
}
if (!fits) {
subset.push_back(arr[i]);
}
}
// return the size of the largest subset
return subset.size();
} int main() {
vector<pair< int , int >> arr = {{1, 3}, {2, 2}, {1, 3}};
cout << getLongest(arr) << endl; // output: 2
arr = {{1, 5}, {2, 4}, {1, 1}, {3, 3}};
cout << getLongest(arr) << endl; // output: 3
return 0;
} |
import java.util.*;
public class Main {
public static int getLongest( int [][] arr)
{
// sort the rectangles in decreasing order of their
// widths
Arrays.sort(arr, new Comparator< int []>() {
@Override public int compare( int [] a, int [] b)
{
return Integer.compare(b[ 1 ], a[ 1 ]);
}
});
// initialize the subset with the widest rectangle
List< int []> subset = new ArrayList<>();
subset.add(arr[ 0 ]);
// iterate over the remaining rectangles
for ( int i = 1 ; i < arr.length; i++) {
int [] rect = arr[i];
// check if the current rectangle can fit in any
// rectangle in the subset
boolean canFit = false ;
for ( int [] r : subset) {
if (rect[ 0 ] <= r[ 0 ] && rect[ 1 ] <= r[ 1 ]) {
canFit = true ;
break ;
}
}
if (!canFit) {
subset.add(rect);
}
}
// return the size of the largest subset
return subset.size();
}
public static void main(String[] args)
{
int [][] arr1 = { { 1 , 3 }, { 2 , 2 }, { 1 , 3 } };
System.out.println(getLongest(arr1)); // output: 2
int [][] arr2
= { { 1 , 5 }, { 2 , 4 }, { 1 , 1 }, { 3 , 3 } };
System.out.println(getLongest(arr2)); // output: 3
}
} |
def getLongest(arr):
# sort the rectangles in decreasing order of their widths
arr.sort(key = lambda x: x[ 1 ], reverse = True )
# initialize the subset with the widest rectangle
subset = [arr[ 0 ]]
# iterate over the remaining rectangles
for rect in arr[ 1 :]:
# check if the current rectangle can fit in any rectangle in the subset
if not any (rect[ 0 ] < = r[ 0 ] and rect[ 1 ] < = r[ 1 ] for r in subset):
subset.append(rect)
# return the size of the largest subset
return len (subset)
# example usage arr = [( 1 , 3 ), ( 2 , 2 ), ( 1 , 3 )]
print (getLongest(arr)) # output: 2
arr = [( 1 , 5 ), ( 2 , 4 ), ( 1 , 1 ), ( 3 , 3 )]
print (getLongest(arr)) # output: 3
|
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{ static int GetLongest(List<Tuple< int , int >> arr)
{
// sort the rectangles in decreasing order of their widths
arr.Sort((a, b) => b.Item2.CompareTo(a.Item2));
// initialize the subset with the widest rectangle
List<Tuple< int , int >> subset = new List<Tuple< int , int >> { arr[0] };
// iterate over the remaining rectangles
foreach ( var rect in arr.Skip(1))
{
// check if the current rectangle can fit in any rectangle in the subset
if (!subset.Any(r => rect.Item1 <= r.Item1 && rect.Item2 <= r.Item2))
{
subset.Add(rect);
}
}
// return the size of the largest subset
return subset.Count;
}
static void Main( string [] args)
{
List<Tuple< int , int >> arr = new List<Tuple< int , int >>
{
Tuple.Create(1, 3),
Tuple.Create(2, 2),
Tuple.Create(1, 3)
};
Console.WriteLine(GetLongest(arr)); // output: 2
arr = new List<Tuple< int , int >>
{
Tuple.Create(1, 5),
Tuple.Create(2, 4),
Tuple.Create(1, 1),
Tuple.Create(3, 3)
};
Console.WriteLine(GetLongest(arr)); // output: 3
}
} |
function getLongest(arr) {
// sort the rectangles in decreasing order of their widths
arr.sort((a, b) => b[1] - a[1]);
// initialize the subset with the widest rectangle
let subset = [arr[0]];
// iterate over the remaining rectangles
for (let i = 1; i < arr.length; i++) {
const rect = arr[i];
// check if the current rectangle can fit in any rectangle in the subset
if (!subset.some(r => rect[0] <= r[0] && rect[1] <= r[1])) {
subset.push(rect);
}
}
// return the size of the largest subset
return subset.length;
} // example usage const arr1 = [ [1, 3],
[2, 2],
[1, 3]
]; console.log(getLongest(arr1)); // output: 2
const arr2 = [ [1, 5],
[2, 4],
[1, 1],
[3, 3]
]; console.log(getLongest(arr2)); // output: 3
|
2 3
Time Complexity:- The time complexity of the above approach is O(n^2), where n is the number of rectangles. However, since we are sorting the rectangles based on their widths, the actual running time may be lower in practice.