CSES Solutions – Rectangle Cutting
Last Updated :
08 Apr, 2024
Given an A X B rectangle, your task is to cut it into squares. On each move you can select a rectangle and cut it into two rectangles in such a way that all side lengths remain integers. What is the minimum possible number of moves?
Examples:
Input: A = 3, B = 5
Output: 3
Explanation: The three moves required to cut the rectangle into squares are:
- Cut the 3 X 5 rectangle into a square of size 3 X 3 and a rectangle of size 2 X 3.
- Cut the 2 X 3 rectangle into a square of size 2 X 2 and a rectangle of size 2 X 1.
- Cut the 2 X 1 rectangle into two squares of size 1 X 1.
Input: A = 5, B = 10
Output: 1
Explanation: Only 1 move is required to cut the rectangle into squares and that is by cutting the 5 X 10 rectangle into 2 squares of size 5 X 5.
Approach: To solve the problem, follow the below idea:
Maintain a dp[][] array such that dp[i][j] stores the minimum number of cuts required to cut an (i X j) rectangle into squares. For an (i X j) rectangle, there can be two cases:
- Case 1: If (i == j), then the rectangle is already a square. So, dp[i][j] = 0.
- Case 2: If (i != j), then we need to make the cut either horizontally or vertically.
- If we make the cut horizontally, then we can cut at any position 1, 2 … i-1. If we cut at position k, then we are left with two pieces of sizes k X j and (i−k) X j. Now, we can look up the number of moves to reduce these to squares in the dp[][] array. We can iterate over all possible values of k and find the cut which requires minimum number of moves, that is dp[i][j] = min(dp[i][j], dp[i][k] + dp[i][j – k] + 1)
- Similarly, if we make the cut vertically, then we can cut at any position 1, 2 … j-1. If we cut at position k, then we are left with two pieces of sizes i X k and i X (j – k). Now, we can look up the number of moves to reduce these to squares in the dp[][] array. We can iterate over all possible values of k and find the cut which requires minimum number of moves, that is dp[i][j] = min(dp[i][j], dp[k][j] + dp[i – k][j] + 1)
After considering over all the possible cuts, dp[A][B] stores the final answer.
Step-by-step algorithm:
- Initialize a dp[][] array with a very large number, say 10^9 such that dp[i][j] stores the minimum number of cuts required to cut an (i X j) rectangle into squares.
- Iterate over all the possible cuts we can make horizontally and iterate over all the cuts we can make vertically.
- If the length and breadth of the rectangle is 0 (i == j), then dp[i][j] = 0.
- Otherwise choose the horizontal or vertical cut which requires minimum total moves to reduce the rectangle to squares.
- Return the final answer as dp[A][B].
Below is the implementation of the algorithm:
C++
#include <bits/stdc++.h>
#define ll long long
using namespace std;
// Function to find the minimum number of moves required to
// cut a rectangle of A X B into squares
ll solve(ll A, ll B)
{
// dp[][] table such that dp[i][j] stores the minimum
// number of cuts required to cut a rectangle of size (i
// X j) into squares
vector<vector<int> > dp(A + 1, vector<int>(B + 1, 1e9));
for (int i = 0; i <= A; i++) {
for (int j = 0; j <= B; j++) {
// If the rectangle is already a square, then 0
// cuts are required
if (i == j) {
dp[i][j] = 0;
}
else {
// Iterate over all the possible cuts we can
// make horizontally
for (int k = 1; k < j; k++) {
dp[i][j]
= min(dp[i][j],
dp[i][k] + dp[i][j - k] + 1);
}
// Iterate over all the possible cuts we can
// make vertically
for (int k = 1; k < i; k++) {
dp[i][j]
= min(dp[i][j],
dp[k][j] + dp[i - k][j] + 1);
}
}
}
}
// Return the minimum number of cuts required to cut a
// rectangle of size (A X B) into squares
return dp[A][B];
}
int main()
{
// Sample Input
int A = 3, B = 5;
cout << solve(A, B) << "\n";
}
Java
import java.util.Arrays;
public class RectangleCutting {
// Function to find the minimum number of moves required to
// cut a rectangle of A X B into squares
static long solve(long A, long B) {
// dp[][] table such that dp[i][j] stores the minimum
// number of cuts required to cut a rectangle of size (i
// X j) into squares
long[][] dp = new long[(int) (A + 1)][(int) (B + 1)];
for (int i = 0; i <= A; i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
for (int i = 0; i <= A; i++) {
for (int j = 0; j <= B; j++) {
// If the rectangle is already a square, then 0
// cuts are required
if (i == j) {
dp[i][j] = 0;
} else {
// Iterate over all the possible cuts we can
// make horizontally
for (int k = 1; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[i][j - k] + 1);
}
// Iterate over all the possible cuts we can
// make vertically
for (int k = 1; k < i; k++) {
dp[i][j] = Math.min(dp[i][j], dp[k][j] + dp[i - k][j] + 1);
}
}
}
}
// Return the minimum number of cuts required to cut a
// rectangle of size (A X B) into squares
return dp[(int) A][(int) B];
}
public static void main(String[] args) {
// Sample Input
int A = 3, B = 5;
System.out.println(solve(A, B));
}
}
// This code is contributed by shivamgupta0987654321
Python3
# Function to find the minimum number of moves required to
# cut a rectangle of A X B into squares
def solve(A, B):
# dp[][] table such that dp[i][j] stores the minimum
# number of cuts required to cut a rectangle of size (i
# X j) into squares
dp = [[float('inf')] * (B + 1) for _ in range(A + 1)]
for i in range(A + 1):
for j in range(B + 1):
# If the rectangle is already a square, then 0
# cuts are required
if i == j:
dp[i][j] = 0
else:
# Iterate over all the possible cuts we can
# make horizontally
for k in range(1, j):
dp[i][j] = min(dp[i][j], dp[i][k] + dp[i][j - k] + 1)
# Iterate over all the possible cuts we can
# make vertically
for k in range(1, i):
dp[i][j] = min(dp[i][j], dp[k][j] + dp[i - k][j] + 1)
# Return the minimum number of cuts required to cut a
# rectangle of size (A X B) into squares
return dp[A][B]
# Sample Input
A = 3
B = 5
print(solve(A, B))
JavaScript
// Function to find the minimum number of moves required to
// cut a rectangle of A X B into squares
function solve(A, B) {
// Create a dp table such that dp[i][j] stores the minimum
// number of cuts required to cut a rectangle of size (i X j) into squares
let dp = new Array(A + 1).fill().map(() => new Array(B + 1).fill(Number.MAX_SAFE_INTEGER));
for (let i = 0; i <= A; i++) {
for (let j = 0; j <= B; j++) {
// If the rectangle is already a square, then 0 cuts are required
if (i === j) {
dp[i][j] = 0;
} else {
// Iterate over all the possible cuts we can make horizontally
for (let k = 1; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[i][j - k] + 1);
}
// Iterate over all the possible cuts we can make vertically
for (let k = 1; k < i; k++) {
dp[i][j] = Math.min(dp[i][j], dp[k][j] + dp[i - k][j] + 1);
}
}
}
}
// Return the minimum number of cuts required to cut a rectangle of size (A X B) into squares
return dp[A][B];
}
// Sample Input
let A = 3, B = 5;
console.log(solve(A, B));
Time Complexity: O(A * A * B + A * B * B), where A and B are the dimensions of the input rectangle.
Auxiliary Space: O(A * B)
Share your thoughts in the comments
Please Login to comment...