Open In App

CSES Solutions – Rectangle Cutting

Last Updated : 08 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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));

Output
3

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)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads