Open In App

Maximum profit from sale of wines

Improve
Improve
Like Article
Like
Save
Share
Report

Given n wines in a row, with integers denoting the cost of each wine respectively. Each year you can sale the first or the last wine in a row. However, the price of wines increases over time. Let the initial profits from the wines be P1, P2, P3…Pn. In the Yth year, the profit from the ith wine will be Y*Pi. For each year, your task is to print “beg” or “end” denoting whether first or last wine should be sold. Also, calculate the maximum profit from all the wines.

Examples : 

Input: Price of wines: 2 4 6 2 5
Output: beg end end beg beg
64
Explanation :

 

Approach: It is a standard Dynamic Programming problem. It initially looks like a greedy problem in which we should sell cheaper of wines each year but the example case (year 2) clearly proves the approach is wrong. Sometimes we need to sell an expensive wine earlier to save relatively costly wines for later years (Here, if 4 were sold in the 2nd year, in the 4th year we had to sell 2 which would be a waste of a heavy coefficient).
The second problem is to “store the strategy” to obtain the calculated price which has a fairly standard method that can be used in other problems as well. The idea is to store the optimal action for each state and use that to navigate through the optimal states starting from the initial state. 

C++




// Program to calculate maximum price of wines
#include <bits/stdc++.h>
using namespace std;
 
#define N 1000
 
int dp[N][N];
 
// This array stores the "optimal action"
// for each state i, j
int sell[N][N];
 
// Function to maximize profit
int maxProfitUtil(int price[], int begin,
                  int end, int n) {
    if (dp[begin][end] != -1)
        return dp[begin][end];
 
    int year = n - (end - begin);
 
    if (begin == end)
        return year * price[begin];   
 
    // x = maximum profit on selling the
    // wine from the front this year
    int x = price[begin] * year +
            maxProfitUtil(price, begin + 1, end, n);
 
    // y = maximum profit on selling the
    // wine from the end this year
    int y = price[end] * year +
            maxProfitUtil(price, begin, end - 1, n);
 
    int ans = max(x, y);
    dp[begin][end] = ans;
 
    if (x >= y)
        sell[begin][end] = 0;
    else
        sell[begin][end] = 1;
 
    return ans;
}
 
// Util Function to calculate maxProfit
int maxProfit(int price[], int n) {
    // resetting the dp table
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            dp[i][j] = -1;
 
    int ans = maxProfitUtil(price, 0, n - 1, n);
 
    int i = 0, j = n - 1;
 
    while (i <= j) {
        // sell[i][j]=0 implies selling the
        // wine from beginning will be more
        // profitable in the long run
        if (sell[i][j] == 0) {
            cout << "beg ";
            i++;
        else {
            cout << "end ";
            j--;
        }
    }
 
    cout << endl;
 
    return ans;
}
 
// Driver code
int main() {
    // Price array
    int price[] = { 2, 4, 6, 2, 5 };
 
    int n = sizeof(price) / sizeof(price[0]);
 
    int ans = maxProfit(price, n);
 
    cout << ans << endl;
 
    return 0;
}


Java




// Program to calculate maximum price of wines
import java.io.*;
 
class GFG {
     
    static int N = 1000;
     
    static int [][]dp = new int[N][N];
     
    // This array stores the "optimal action"
    // for each state i, j
    static int [][]sell = new int[N][N];
     
    // Function to maximize profit
    static int maxProfitUtil(int price[],
                   int begin, int end, int n)
    {
        if (dp[begin][end] != -1)
            return dp[begin][end];
     
        int year = n - (end - begin);
     
        if (begin == end)
            return year * price[begin];
     
        // x = maximum profit on selling the
        // wine from the front this year
        int x = price[begin] * year +
                maxProfitUtil(price, begin + 1,
                                       end, n);
     
        // y = maximum profit on selling the
        // wine from the end this year
        int y = price[end] * year +
                maxProfitUtil(price, begin,
                                  end - 1, n);
     
        int ans = Math.max(x, y);
        dp[begin][end] = ans;
     
        if (x >= y)
            sell[begin][end] = 0;
        else
            sell[begin][end] = 1;
     
        return ans;
    }
     
    // Util Function to calculate maxProfit
    static int maxProfit(int price[], int n)
    {
         
        // resetting the dp table
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                dp[i][j] = -1;
     
        int ans = maxProfitUtil(price, 0,
                                  n - 1, n);
     
        int i = 0, j = n - 1;
     
        while (i <= j) {
     
            // sell[i][j]=0 implies selling
            // the wine from beginning will
            // be more profitable in the
            // long run
            if(sell[i][j] == 0){
                System.out.print( "beg ");
                i++;
            }
            else
            {
                System.out.print( "end ");
                j--;
            }
        }
     
        System.out.println();
     
        return ans;
    }
     
    // Driver code
    public static void main (String[] args)
    {
        // Price array
        int price[] = { 2, 4, 6, 2, 5 };
     
        int n = price.length;
     
        int ans = maxProfit(price, n);
     
        System.out.println( ans );
    }
}
 
// This code is contributed by anuj_67.


Python3




# Python3 Program to calculate
# maximum price of wines
N = 1000
dp = [ [-1 for col in range(N)]    
           for row in range(N)]
 
# This array stores the "optimal action"
# for each state i, j
sell = [ [0 for col in range(N)]
            for row in range(N)]
 
# Function to maximize profit
def maxProfitUtil(price, begin, end, n):
     
    if (dp[begin][end] != -1):
        return dp[begin][end]
 
    year = n - (end - begin)
 
    if (begin == end):
        return year * price[begin]
 
    # x = maximum profit on selling the
    # wine from the front this year
    x = price[begin] * year + \
        maxProfitUtil(price, begin + 1, end, n)
 
    # y = maximum profit on selling the
    # wine from the end this year
    y = price[end] * year + \
        maxProfitUtil(price, begin, end - 1, n)
 
    ans = max(x, y)
    dp[begin][end] = ans
 
    if (x >= y):
        sell[begin][end] = 0
    else:
        sell[begin][end] = 1
 
    return ans
 
# Util Function to calculate maxProfit
def maxProfit(price, n):
 
    ans = maxProfitUtil(price, 0, n - 1, n)
 
    i = 0
    j = n - 1
 
    while (i <= j):
         
        # sell[i][j]=0 implies selling the
        # wine from beginning will be more
        # profitable in the long run
        if (sell[i][j] == 0):
            print("beg", end = " ")
            i = i + 1
        else:
            print("end", end = " ")
            j = j - 1
     
    print(" ")
    return ans
 
# Driver code
 
# Price array
price = [ 2, 4, 6, 2, 5 ]
 
size = 5
 
ans = maxProfit(price, size);
 
print(ans)
 
# This code is contributed by ashutosh450


C#




// C# Program to calculate maximum
// price of wines
using System;
 
class GFG {
 
    static int N = 1000;
    static int[,] dp = new int[N, N];
 
    // This array stores the "optimal action"
    // for each state i, j
    static int[,] sell = new int[N, N];
 
    // Function to maximize profit
    static int maxProfitUtil(int[] price, int begin, int end, int n)
    {
        // Check if the result for this state is already calculated
        if (dp[begin, end] != -1)
            return dp[begin, end];
 
        // Calculate the current year
        int year = n - (end - begin);
 
        if (begin == end)
            return year * price[begin];
 
        // Calculate maximum profit by selling from the front
        int x = price[begin] * year +
                maxProfitUtil(price, begin + 1, end, n);
 
        // Calculate maximum profit by selling from the end
        int y = price[end] * year +
                maxProfitUtil(price, begin, end - 1, n);
 
        // Choose the maximum of the two options
        int ans = Math.Max(x, y);
        dp[begin, end] = ans;
 
        // Store the optimal action: 0 for selling from the front, 1 for selling from the end
        if (x >= y)
            sell[begin, end] = 0;
        else
            sell[begin, end] = 1;
 
        return ans;
    }
 
    // Util Function to calculate maxProfit
    static int maxProfit(int[] price, int n)
    {
        int i, j;
 
        // Resetting the dp table
        for (i = 0; i < N; i++)
            for (j = 0; j < N; j++)
                dp[i, j] = -1;
 
        // Calculate the maximum profit
        int ans = maxProfitUtil(price, 0, n - 1, n);
 
        i = 0; j = n - 1;
 
        // Print the optimal actions (selling from the beginning or end)
        while (i <= j) {
 
            // sell[i][j]=0 implies selling
            // the wine from beginning will
            // be more profitable in the
            // long run
            if (sell[i, j] == 0) {
                Console.Write("beg ");
                i++;
            }
            else {
                Console.Write("end ");
                j--;
            }
        }
 
        Console.WriteLine();
 
        return ans;
    }
 
    // Driver Code
    public static void Main()
    {
        // Price array
        int[] price = { 2, 4, 6, 2, 5 };
        int n = price.Length;
 
        // Call the maxProfit function and print the result
        int ans = maxProfit(price, n);
        Console.WriteLine(ans);
    }
}
 
// This code is contributed by anuj_67.


Javascript




<script>
    // Program to calculate maximum price of wines
     
    let N = 1000;
       
    let dp = new Array(N);
       
    // This array stores the "optimal action"
    // for each state i, j
    let sell = new Array(N);
     
    for(let i = 0; i < N; i++)
    {
        dp[i] = new Array(N);
        sell[i] = new Array(N);
        for(let j = 0; j < N; j++)
        {
            dp[i][j] = 0;
            sell[i][j] = 0;
        }
    }
       
    // Function to maximize profit
    function maxProfitUtil(price, begin, end, n)
    {
        if (dp[begin][end] != -1)
            return dp[begin][end];
       
        let year = n - (end - begin);
       
        if (begin == end)
            return year * price[begin];
       
        // x = maximum profit on selling the
        // wine from the front this year
        let x = price[begin] * year +
                maxProfitUtil(price, begin + 1,
                                       end, n);
       
        // y = maximum profit on selling the
        // wine from the end this year
        let y = price[end] * year +
                maxProfitUtil(price, begin,
                                  end - 1, n);
       
        let ans = Math.max(x, y);
        dp[begin][end] = ans;
       
        if (x >= y)
            sell[begin][end] = 0;
        else
            sell[begin][end] = 1;
       
        return ans;
    }
       
    // Util Function to calculate maxProfit
    function maxProfit(price, n)
    {
           
        // resetting the dp table
        for (let i = 0; i < N; i++)
            for (let j = 0; j < N; j++)
                dp[i][j] = -1;
       
        let ans = maxProfitUtil(price, 0, n - 1, n);
       
        let i = 0, j = n - 1;
       
        while (i <= j) {
       
            // sell[i][j]=0 implies selling
            // the wine from beginning will
            // be more profitable in the
            // long run
            if(sell[i][j] == 0){
                document.write( "beg ");
                i++;
            }
            else
            {
                document.write( "end ");
                j--;
            }
        }
       
        document.write("</br>");
       
        return ans;
    }
     
    // Price array
    let price = [ 2, 4, 6, 2, 5 ];
    let n = price.length;
    let ans = maxProfit(price, n);
    document.write( ans );
     
    // This code is contributed by divyeshrabadiya07.
</script>


Output

beg end end beg beg 
64







Time Complexity: O(n2)
Auxiliary Space: O(n2)

Efficient approach : Using DP Tabulation method ( Iterative approach )

The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Steps to solve this problem :

  • Create a dp to store the solution of the subproblems.
  • Create another table sell to storing information when to sell.
  • Initialize the dp and sell with base cases
  • Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in dp.
  • Return the final solution stored in dp[0][n-1].

Implementation :

C++




#include <bits/stdc++.h>
using namespace std;
 
#define N 1000
 
int dp[N][N];  // Dynamic programming table for storing maximum profits
int sell[N][N];  // Table for storing information about when to sell
 
int maxProfit(int price[], int n) {
    // Initialize the diagonal elements of the tables
    for (int i = 0; i < n; i++) {
        dp[i][i] = n * price[i];  // If only one year is left, sell at the current price
        sell[i][i] = 0;  // Mark as 'beg' (beginning) because only one year is left
    }
 
    // Calculate the maximum profit for different lengths of the subarray
    for (int len = 1; len < n; len++) {
        for (int i = 0; i < n - len; i++) {
            int j = i + len;
            int year = n - (j - i);  // Calculate the current year
 
            int x = price[i] * year + dp[i + 1][j];  // Sell at the current year price and calculate the profit for remaining subarray
            int y = price[j] * year + dp[i][j - 1];  // Sell at the last year price and calculate the profit for remaining subarray
 
            // Choose the option that gives maximum profit
            if (x >= y) {
                dp[i][j] = x;  // Maximum profit if we sell at the current price
                sell[i][j] = 0;  // Mark as 'beg' (beginning) because we sell at the current price
            } else {
                dp[i][j] = y;  // Maximum profit if we sell at the last year price
                sell[i][j] = 1;  // Mark as 'end' because we sell at the last year price
            }
        }
    }
 
    // Determine the sequence of selling 'beg' and 'end'
    int i = 0, j = n - 1;
    while (i <= j) {
        if (sell[i][j] == 0) {
            cout << "beg ";
            i++;
        } else {
            cout << "end ";
            j--;
        }
    }
    cout << endl;
 
    return dp[0][n - 1];  // Return the maximum profit for the entire array
}
 
int main() {
    int price[] = {2, 4, 6, 2, 5};
    int n = sizeof(price) / sizeof(price[0]);
    int ans = maxProfit(price, n);
    cout << ans << endl;
    return 0;
}


Java




class Main {
    static final int N = 1000;
 
    static int[][] dp = new int[N][N];  // Dynamic programming table for storing maximum profits
    static int[][] sell = new int[N][N];  // Table for storing information about when to sell
 
    static int maxProfit(int price[], int n) {
        // Initialize the diagonal elements of the tables
        for (int i = 0; i < n; i++) {
            dp[i][i] = n * price[i];  // If only one year is left, sell at the current price
            sell[i][i] = 0// Mark as 'beg' (beginning) because only one year is left
        }
 
        // Calculate the maximum profit for different lengths of the subarray
        for (int len = 1; len < n; len++) {
            for (int i = 0; i < n - len; i++) {
                int j = i + len;
                int year = n - (j - i);  // Calculate the current year
 
                int x = price[i] * year + dp[i + 1][j];  // Sell at the current year price and calculate the profit for remaining subarray
                int y = price[j] * year + dp[i][j - 1];  // Sell at the last year price and calculate the profit for remaining subarray
 
                // Choose the option that gives maximum profit
                if (x >= y) {
                    dp[i][j] = x;  // Maximum profit if we sell at the current price
                    sell[i][j] = 0// Mark as 'beg' (beginning) because we sell at the current price
                } else {
                    dp[i][j] = y;  // Maximum profit if we sell at the last year price
                    sell[i][j] = 1// Mark as 'end' because we sell at the last year price
                }
            }
        }
 
        // Determine the sequence of selling 'beg' and 'end'
        int i = 0, j = n - 1;
        while (i <= j) {
            if (sell[i][j] == 0) {
                System.out.print("beg ");
                i++;
            } else {
                System.out.print("end ");
                j--;
            }
        }
        System.out.println();
 
        return dp[0][n - 1];  // Return the maximum profit for the entire array
    }
 
    public static void main(String args[]) {
        int price[] = {2, 4, 6, 2, 5};
        int n = price.length;
        int ans = maxProfit(price, n);
        System.out.println(ans);
    }
}


Python3




def maxProfit(price):
    n = len(price)
    dp = [[0] * n for _ in range(n)]
    sell = [[0] * n for _ in range(n)]
 
    # Initialize the diagonal elements of the tables
    for i in range(n):
        dp[i][i] = n * price[i]  # If only one year is left, sell at the current price
        sell[i][i] = 0  # Mark as 'beg' (beginning) because only one year is left
 
    # Calculate the maximum profit for different lengths of the subarray
    for length in range(1, n):
        for i in range(n - length):
            j = i + length
            year = n - (j - i)  # Calculate the current year
 
            x = price[i] * year + dp[i + 1][j]  # Sell at the current year price and calculate the profit for the remaining subarray
            y = price[j] * year + dp[i][j - 1# Sell at the last year price and calculate the profit for the remaining subarray
 
            # Choose the option that gives maximum profit
            if x >= y:
                dp[i][j] = # Maximum profit if we sell at the current price
                sell[i][j] = 0  # Mark as 'beg' (beginning) because we sell at the current price
            else:
                dp[i][j] = # Maximum profit if we sell at the last year price
                sell[i][j] = 1  # Mark as 'end' because we sell at the last year price
 
    # Determine the sequence of selling 'beg' and 'end'
    i, j = 0, n - 1
    while i <= j:
        if sell[i][j] == 0:
            print("beg", end=" ")
            i += 1
        else:
            print("end", end=" ")
            j -= 1
    print()
 
    return dp[0][n - 1# Return the maximum profit for the entire array
 
price = [2, 4, 6, 2, 5]
ans = maxProfit(price)
print(ans)


C#




using System;
 
class MaxProfit
{
    // Function to calculate maximum profit and output the buying/selling actions
    public static int MaxProfitCalc(int[] price)
    {
        int n = price.Length;
        int[][] dp = new int[n][];  // Array to store maximum profit values
        int[][] sell = new int[n][];  // Array to store buying/selling actions
 
        // Initializing arrays
        for (int i = 0; i < n; i++)
        {
            dp[i] = new int[n];
            sell[i] = new int[n];
        }
 
        // Initialize base cases for one-day transactions
        for (int i = 0; i < n; i++)
        {
            dp[i][i] = n * price[i];
            sell[i][i] = 0;  // No selling on the same day
        }
 
        // Dynamic Programming to fill in the dp and sell arrays
        for (int length = 1; length < n; length++)
        {
            for (int i = 0; i < n - length; i++)
            {
                int j = i + length;
                int year = n - (j - i);
 
                int x = price[i] * year + dp[i + 1][j];  // If buying at the beginning is profitable
                int y = price[j] * year + dp[i][j - 1];  // If buying at the end is profitable
 
                // Choose the more profitable option and update the sell array accordingly
                if (x >= y)
                {
                    dp[i][j] = x;
                    sell[i][j] = 0;  // 0 represents buying at the beginning
                }
                else
                {
                    dp[i][j] = y;
                    sell[i][j] = 1;  // 1 represents buying at the end
                }
            }
        }
 
        // Output the buying/selling actions
        int iVal = 0;
        int jVal = n - 1;
        while (iVal <= jVal)
        {
            if (sell[iVal][jVal] == 0)
            {
                Console.Write("beg ");  // Output "beg" for buying at the beginning
                iVal++;
            }
            else
            {
                Console.Write("end ");  // Output "end" for buying at the end
                jVal--;
            }
        }
        Console.WriteLine();
 
        return dp[0][n - 1];  // Return the maximum profit
    }
 
    // Main function to demonstrate the MaxProfitCalc function
    public static void Main(string[] args)
    {
        int[] price = { 2, 4, 6, 2, 5 };
        int ans = MaxProfitCalc(price);
        Console.WriteLine(ans);
    }
}


Javascript




function maxProfit(price) {
    const n = price.length;
    const dp = Array.from({ length: n }, () => Array(n).fill(0));
    const sell = Array.from({ length: n }, () => Array(n).fill(0));
 
    // Initialize the diagonal elements of the tables
    for (let i = 0; i < n; i++) {
        dp[i][i] = n * price[i];  // If only one year is left, sell at the current price
        sell[i][i] = 0;  // Mark as 'beg' (beginning) because only one year is left
    }
 
    // Calculate the maximum profit for different lengths of the subarray
    for (let len = 1; len < n; len++) {
        for (let i = 0; i < n - len; i++) {
            const j = i + len;
            const year = n - (j - i);  // Calculate the current year
 
            const x = price[i] * year + dp[i + 1][j];  // Sell at the current year price and calculate the profit for remaining subarray
            const y = price[j] * year + dp[i][j - 1];  // Sell at the last year price and calculate the profit for remaining subarray
 
            // Choose the option that gives maximum profit
            if (x >= y) {
                dp[i][j] = x;  // Maximum profit if we sell at the current price
                sell[i][j] = 0;  // Mark as 'beg' (beginning) because we sell at the current price
            } else {
                dp[i][j] = y;  // Maximum profit if we sell at the last year price
                sell[i][j] = 1;  // Mark as 'end' because we sell at the last year price
            }
        }
    }
 
    // Determine the sequence of selling 'beg' and 'end'
    let i = 0,
        j = n - 1;
    const sequence = [];
    while (i <= j) {
        if (sell[i][j] === 0) {
            sequence.push("beg");
            i++;
        } else {
            sequence.push("end");
            j--;
        }
    }
    console.log(sequence.join(" "));
 
    return dp[0][n - 1];  // Return the maximum profit for the entire array
}
 
const price = [2, 4, 6, 2, 5];
const ans = maxProfit(price);
console.log(ans);


Output

beg end end beg beg 
64








Time Complexity: O(n^2)
Auxiliary Space: O(n^2)



Last Updated : 04 Dec, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads