Rod Cutting Problem

Rod Cutting Problem

Problem Statement

Given a rod of length n  and array prices of length n denoting the cost of pieces of the rod of length 1 to n, find the maximum amount that can be made if the rod is cut up optimally.

Sample Test Cases

Input 1:

n = 8, prices[] = [1, 3, 4, 5, 7, 9, 10, 11]

Output 1:

12

Explanation 1:

Cutting the rod into 2 rods of length 2 and 6 gives us a cost of 3 + 9  = 12, which is optimal.

Input 2:

n = 4, prices[] = [1, 1, 1, 6]

Output 2:

6

Explanation 2:

It can be seen that performing no cuts and taking the entire rod as a whole can lead to the optimal answer of 6.

Naive Approach

We can solve this problem naively with a recursive backtracking-based solution. By generating all possible configurations of different pieces and finding the maximum among them, we can get our optimal solution.

Code / Implementation:

C++ Code

int maximumProfit(vector < int > & prices, int n) {
  if (n == 0) {
    return 0;
  }
  int maxProfit = INT_MIN;
  for (int i = 1; i <= n; i++) {
    maxProfit = max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i));
  }
  return maxProfit;
}

Java Code

 public static int maximumProfit(int[] prices, int n) {
   if (n == 0) {
     return 0;
   }
   int maxProfit = Integer.MIN_VALUE;
   for (int i = 1; i <= n; i++) {
     maxProfit = Math.max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i));
   }
   return maxProfit;
 }

Python Code

def maximumProfit(prices, n):
    if n == 0:
        return n
    maxProfit = -999999
    for i in range(1, n + 1):
        maxProfit = max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i))
    return maxProfit

Complexity Analysis:

  • Time Complexity: Exponential
  • Space Complexity: O(1) if recursion stack space is not considered

Memoization Based Approach

Considering the above recursion tree for n = 4, we can observe that there are multiple values, for which the function is being called again and again. Rather than using these redundant function calls, we can calculate the value of the function call once, and memoize it to use for future operations. Just by memoizing the results using an array or a hashmap, we can reduce the time complexity of the program from exponential to polynomial time complexity.

Now to memoize the function calls, into some relevant data structure, we need to find out our DP states. Here, we find from the above diagram that the overlapping subproblem depends only on the length of the current piece of the rod (n). So, our DP state will be the optimal cost which can be obtained if the length of the rod is n. This leads us to a 1D DP solution, which has,

  • O(n) states
  • O(n) time per transition  

Implementation:

C++ Code

int maximumProfit(vector < int > & prices, int n, vector < int > & dp) {
  if (n == 0) {
    return 0;
  }
  if (dp[n] != -1) {
    return dp[n];
  }
  int maxProfit = INT_MIN;
  for (int i = 1; i <= n; i++) {
    maxProfit = max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i, dp));
  }
  return dp[n] = maxProfit;
}
int getMaxProfit(vector < int > & a, int n) {
  vector < int > dp(n + 1, -1);
  return maximumProfit(a, n, dp);
}

Java Code

public static int maximumProfit(int[] prices, int n, int[] dp) {
  if (n == 0) {
    return 0;
  }
  if (dp[n] != -1) {
    return dp[n];
  }
  int maxProfit = Integer.MIN_VALUE;
  for (int i = 1; i <= n; i++) {
    maxProfit = Math.max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i, dp));
  }
  return dp[n] = maxProfit;
}
public static int getMaxProfit(int[] a, int n) {
  int[] dp = new int[n + 1];
  for (int i = 0; i <= n; i++) {
    dp[i] = -1;
  }
  return maximumProfit(a, n, dp);
}

Python Code

def maximumProfit(prices, n, dp):
    if n == 0:
        return n
    if dp[n] != -1:
        return dp[n]
    maxProfit = -999999
    for i in range(1, n + 1):
        maxProfit = max(maxProfit, prices[i - 1] + maximumProfit(prices, n - i, dp))
    dp[n] = maxProfit
    return dp[n]


def getMaxProfit(prices, n):
    dp = [-1] * (n + 1)
    return maximumProfit(prices, n, dp)

Complexity Analysis:

  • Time Complexity: O(n2)
  • Space Complexity: O(n)

Iterative Dynamic Programming Approach

Similar to the memoization approach, we can also solve this problem using tabulation-based Dynamic Programming. In any dynamic programming problem, there are 2 things that are to be considered,

  • States: DP[i] = Best possible price for a rod of length i.
  • Transitions: DP[i] = max(prices[j] + DP[i – j – 1]) overall values of j from [0, i – 1]

Using the above states and transitions, we can tabulate the optimal answer for all possible lengths of the rod, and finally, our required result will be stored in DP[n].

Implementation:

C++ Code

int maximumProfit(vector < int > & prices, int n) {
  vector < int > dp(n + 1, 0);
  if (n <= 0) {
    return 0;
  }
  int maxVal = INT_MIN;
  for (int i = 1; i <= n; i++) {
    for (int j = 0; j < i; j++) {
      maxVal = max(maxVal, prices[j] + dp[i - j - 1]);
    }
    dp[i] = maxVal;
  }
  return dp[n];
}

Java Code

public static int maximumProfit(int[] prices, int n) {
  int[] dp = new int[n + 1];
  if (n <= 0) {
    return 0;
  }
  int maxVal = Integer.MIN_VALUE;
  for (int i = 1; i <= n; i++) {
    for (int j = 0; j < i; j++) {
      maxVal = Math.max(maxVal, prices[j] + dp[i - j - 1]);
    }
    dp[i] = maxVal;
  }
  return dp[n];
}

Python Code

def maximumProfit(prices, n):
    dp = [0] * (n + 1)
    if n <= 0:
        return 0
    maxVal = -999999
    for i in range(1, n + 1):
        for j in range(i):
            maxVal = max(maxVal, prices[j] + dp[i - j - 1])
        dp[i] = maxVal
    return dp[n]

Complexity Analysis:

  • Time Complexity: O(n2)
  • Space Complexity: O(n)

Practice Problem:

FAQs

Q.1: What is the time complexity per state transition of the Dynamic Programming approach?

Ans: The time complexity is O(n) per transition.

Q.2: How to identify that a problem can be solved by Dynamic Programming?

Ans: A problem can be solved using Dynamic Programming if it contains some Optimal Substructure and Overlapping Subproblems.

Previous Post

Dijkstra’s Shortest Path Algorithm

Next Post

Trapping Rain Water