Rod Cutting


Rod Cutting - GFG


Problem Statement

You are given a rod of length n and a price array of size n where price[i] denotes the price of a rod of length i+1. You can cut the rod in various sizes and sell the pieces. Find the maximum total value you can obtain by cutting up the rod and selling the pieces.


Examples

Input

n = 8  
price[] = {1, 5, 8, 9, 10, 17, 17, 20}

Output

22

Choice Diagram

At each index i, we have two choices:

          +------------------+
          |  Rod Length = i  |
          +------------------+
            /           \
         Pick         Not Pick
     Add price[i]     Move to i-1
     Reduce length     Same length

Step 1: Recursion (TLE)

IBH

public class Solution {
    public static int cutRod(int[] price, int n) {
        return f(price.length - 1, n, price);
    }

    static int f(int i, int length, int[] price) {
        if (i == 0) {
            return length * price[0]; // all 1-length cuts
        }

        int notPick = f(i - 1, length, price);
        int pick = Integer.MIN_VALUE;
        int rodLength = i + 1;
        if (rodLength <= length) {
            pick = price[i] + f(i, length - rodLength, price); // pick same index (unbounded)
        }

        return Math.max(pick, notPick);
    }
}

Step 2: Memoization

import java.util.*;

public class Solution {
    public static int cutRod(int[] price, int n) {
        int[][] dp = new int[n][n + 1];
        for (int[] row : dp) Arrays.fill(row, -1);
        return f(n - 1, n, price, dp);
    }

    static int f(int i, int length, int[] price, int[][] dp) {
        if (i == 0) {
            return length * price[0];
        }

        if (dp[i][length] != -1) return dp[i][length];

        int notPick = f(i - 1, length, price, dp);
        int pick = Integer.MIN_VALUE;
        int rodLength = i + 1;
        if (rodLength <= length) {
            pick = price[i] + f(i, length - rodLength, price, dp);
        }

        return dp[i][length] = Math.max(pick, notPick);
    }
}

Step 3: Tabulation (Bottom-Up DP)

import java.util.*;

public class Solution {
    public static int cutRod(int[] price, int n) {
        int[][] dp = new int[n][n + 1];

        // Base case: only using 1-length rods
        for (int length = 0; length <= n; length++) {
            dp[0][length] = length * price[0];
        }

        for (int i = 1; i < n; i++) {
            for (int length = 0; length <= n; length++) {
                int notPick = dp[i - 1][length];
                int pick = Integer.MIN_VALUE;
                int rodLength = i + 1;

                if (rodLength <= length) {
                    pick = price[i] + dp[i][length - rodLength];
                }

                dp[i][length] = Math.max(pick, notPick);
            }
        }

        return dp[n - 1][n];
    }
}

Step 4: Space Optimization

We just need the previous row and current row, so optimize using two 1D arrays:

import java.util.*;

public class Solution {
    public static int cutRod(int[] price, int n) {
        int[] prev = new int[n + 1];

        // Base case
        for (int length = 0; length <= n; length++) {
            prev[length] = length * price[0];
        }

        for (int i = 1; i < n; i++) {
            int[] curr = new int[n + 1];
            for (int length = 0; length <= n; length++) {
                int notPick = prev[length];
                int pick = Integer.MIN_VALUE;
                int rodLength = i + 1;

                if (rodLength <= length) {
                    pick = price[i] + curr[length - rodLength]; // use curr to allow unlimited cuts
                }

                curr[length] = Math.max(pick, notPick);
            }
            prev = curr;
        }

        return prev[n];
    }
}

Conclusion

Approach Time Complexity Space Complexity
Recursion Exponential O(n)
Memoization O(n²) O(n²)
Tabulation O(n²) O(n²)
Space Optimized O(n²) O(n)