Maximum profit using M money and reducing half price of at most K stocks
Last Updated :
07 Nov, 2023
Given the cost[] and profit[] of N stocks and K tickets, the task is to find the maximum total profit that can be obtained from M initial amount of money using K tickets.
Note: A ticket can be used to reduce the cost of any stock to half of the original price and on a particular stock, a ticket can be used only once.
Examples:
Input: N = 3, cost[] = {2, 4, 5}, profit[] = {20, 17, 15}, K = 1, M = 4
Output: 37
Explanation: The most optimal case is when we take the 1st stock at regular cost and use a ticket for 2nd item. Total amount of money spent = (2 + (4 / 2)) = 4 ≤ M. Total Profit obtained is = 20 + 17 = 37
Input: N = 3, cost[] = {4, 4, 3}, profit[] = {12, 14, 7}, K = 2, M = 5
Output: 26
Explanation: The most optimal case is when we take the 1st stock using the 1st ticket and the 2nd item using the 2nd ticket. Total amount of money spent = ((4 / 2) + (4 / 2)) = 4 ≤ M. Total Profit obtained is = 12 +14 = 26
Naive Approach: Implement the idea below to solve the problem:
It is always beneficial to use the maximum number of tickets because it will reduce the price of the stock. For each item there are 3 choices:
- Don’t consider the current stock.
- Take the current but don’t use the ticket.
- Take the current and use the ticket.
Steps were taken to solve the problem:
- Initialise the integer variable Ans for storing maximum profit earned.
- To consider all subsets of items, for a given element we have 3 choices:
- Don’t take the current Stock, then the current amount left will be M, Ans remain the same.
- If possible(M ≥ cost[i]), take the current stock and add its profit value to the Ans then the current money left will be M – cost[i].
- If the ticket is used, add its profit value to the Ans, then the current money left will be M – cost[i]/2.
- Return maximum Ans of the above three possible cases.
Below is the code implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
int maxProfit( int i, int N, int cost[],
int profit[], int K, int M)
{
if (i == N) {
return 0;
}
int ans1 = maxProfit(i + 1, N, cost,
profit, K, M);
int ans2 = INT_MIN;
int ans3 = INT_MIN;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost,
profit, K, M - cost[i]);
}
if (K > 0) {
int newcost = cost[i] / 2;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return max(ans1, max(ans2, ans3));
}
int main()
{
int cost[] = { 2, 4, 5 };
int profit[] = { 20, 17, 15 };
int N = sizeof (cost) / sizeof (cost[0]);
int K = 1, M = 4;
cout << maxProfit(0, N, cost, profit, K, M);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int maxProfit( int i, int N, int [] cost,
int [] profit, int K, int M)
{
if (i == N) {
return 0 ;
}
int ans1 = maxProfit(i + 1 , N, cost, profit, K, M);
int ans2 = Integer.MIN_VALUE;
int ans3 = Integer.MIN_VALUE;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1 , N, cost, profit, K,
M - cost[i]);
}
if (K > 0 ) {
int newcost = cost[i] / 2 ;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1 , N, cost, profit,
K - 1 , M - newcost);
}
}
return Math.max(ans1, Math.max(ans2, ans3));
}
public static void main(String[] args)
{
int [] cost = { 2 , 4 , 5 };
int [] profit = { 20 , 17 , 15 };
int N = cost.length;
int K = 1 , M = 4 ;
System.out.print(
maxProfit( 0 , N, cost, profit, K, M));
}
}
|
Python3
import sys
def maxProfit(i,N,cost,profit,K,M):
if (i = = N):
return 0
ans1 = maxProfit(i + 1 ,N,cost,profit,K,M)
ans2 = - 1 * sys.maxsize
ans3 = - 1 * sys.maxsize
if (M > = cost[i]):
ans2 = profit[i] + maxProfit(i + 1 , N, cost, profit, K, M - cost[i])
if (K > 0 ):
newcost = cost[i] / / 2
if (M > = newcost):
ans3 = profit[i] + maxProfit(i + 1 , N, cost, profit, K - 1 , M - newcost)
return max (ans1, max (ans2, ans3))
cost = [ 2 , 4 , 5 ]
profit = [ 20 , 17 , 15 ]
N = len (cost)
K = 1
M = 4
print (maxProfit( 0 , N, cost, profit, K, M))
|
C#
using System;
public class GFG {
public static int maxProfit( int i, int N, int [] cost,
int [] profit, int K, int M)
{
if (i == N) {
return 0;
}
int ans1 = maxProfit(i + 1, N, cost, profit, K, M);
int ans2 = Int32.MinValue;
int ans3 = Int32.MinValue;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost, profit, K,
M - cost[i]);
}
if (K > 0) {
int newcost = ( int )(cost[i] / 2);
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return Math.Max(ans1, Math.Max(ans2, ans3));
}
static public void Main()
{
int [] cost = { 2, 4, 5 };
int [] profit = { 20, 17, 15 };
int N = cost.Length;
int K = 1, M = 4;
Console.WriteLine(
maxProfit(0, N, cost, profit, K, M));
}
}
|
Javascript
function maxProfit(i, N, cost,profit, K, M)
{
if (i == N) {
return 0;
}
let ans1 = maxProfit(i + 1, N, cost,
profit, K, M);
let ans2 = Number.MIN_VALUE;
let ans3 = Number.MIN_VALUE;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost,
profit, K, M - cost[i]);
}
if (K > 0) {
let newcost = cost[i] / 2;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return Math.max(ans1, Math.max(ans2, ans3));
}
let cost = [ 2, 4, 5 ];
let profit = [ 20, 17, 15 ];
let N = cost.length, K = 1, M = 4;
console.log(maxProfit(0, N, cost, profit, K, M));
|
Time Complexity = O(3N)
Auxiliary Space = O(1)
Efficient Approach using Dynamic Programming:
The above approach has overlapping subproblems as can be seem below. Say:
M = 5, N = 3, K = 2, Cost[] = {4, 4, 3}, Profit[]={ 12, 14, 7}
Let X(M, 0, K) represent the given state that M initial money and K tickets and at index 0:
- Left move – 1st case – Don’t take current element
- Down move – 2nd case – Take the current element
- Right move – 3rd case – Take the current element with Ticket.
The recursion tree for the test case
So we can use the concept of dynamic programming.
Follow the steps mentioned below to implement the idea:
- Initialize a 3D array (say dp[][][]) to store the value of each state as shown above.
- Now use the same recursion as the previous approach.
- To reduce the calculation, if a state which is already calculated is encountered, return the maximum profit for that state.
- The value stored at the state (M, 0, K) is the required answer.
Below is the implementation of the efficient approach.
C++
#include <bits/stdc++.h>
using namespace std;
int dp[1001][501][11];
int maxProfit( int i, int N, int cost[], int profit[], int K,
int M)
{
if (i == N) {
return 0;
}
if (dp[M][i][K] != -1) {
return dp[M][i][K];
}
int ans1 = maxProfit(i + 1, N, cost, profit, K, M);
int ans2 = INT_MIN;
int ans3 = INT_MIN;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost, profit, K,
M - cost[i]);
}
if (K > 0) {
int newcost = cost[i] / 2;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return dp[M][i][K] = max(ans1, max(ans2, ans3));
}
int main()
{
int N = 3;
int cost[3] = { 2, 4, 5 };
int profit[3] = { 20, 17, 15 };
int K = 1;
int M = 4;
memset (dp, -1, sizeof (dp));
cout << maxProfit(0, N, cost, profit, K, M);
return 0;
}
|
Java
import java.util.*;
public class GFG {
static int dp[][][] = new int [ 1001 ][ 501 ][ 11 ];
public static int maxProfit( int i, int N, int cost[],
int profit[], int K, int M)
{
if (i == N) {
return 0 ;
}
if (dp[M][i][K] != - 1 ) {
return dp[M][i][K];
}
int ans1 = maxProfit(i + 1 , N, cost, profit, K, M);
int ans2 = Integer.MIN_VALUE;
int ans3 = Integer.MIN_VALUE;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1 , N, cost, profit, K,
M - cost[i]);
}
if (K > 0 ) {
int newcost = cost[i] / 2 ;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1 , N, cost, profit,
K - 1 , M - newcost);
}
}
return dp[M][i][K]
= Math.max(ans1, Math.max(ans2, ans3));
}
public static void main(String args[])
{
int N = 3 ;
int cost[] = { 2 , 4 , 5 };
int profit[] = { 20 , 17 , 15 };
int K = 1 ;
int M = 4 ;
for ( int i = 0 ; i < 1001 ; i++) {
for ( int j = 0 ; j < 501 ; j++) {
for ( int k = 0 ; k < 11 ; k++) {
dp[i][j][k] = - 1 ;
}
}
}
System.out.println(
maxProfit( 0 , N, cost, profit, K, M));
}
}
|
Python3
dp = [[[ - 1 for k in range ( 11 )] for j in range ( 501 )] for i in range ( 1001 )]
def maxProfit(i, N, cost, profit, K, M):
if i = = N:
return 0
if dp[M][i][K] ! = - 1 :
return dp[M][i][K]
ans1 = maxProfit(i + 1 , N, cost, profit, K, M)
ans2 = float ( '-inf' )
ans3 = float ( '-inf' )
if M > = cost[i]:
ans2 = profit[i] + maxProfit(i + 1 , N, cost, profit, K, M - cost[i])
if K > 0 :
newcost = cost[i] / / 2
if M > = newcost:
ans3 = profit[i] + maxProfit(i + 1 , N, cost, profit, K - 1 , M - newcost)
dp[M][i][K] = max (ans1, max (ans2, ans3))
return dp[M][i][K]
N = 3
cost = [ 2 , 4 , 5 ]
profit = [ 20 , 17 , 15 ]
K = 1
M = 4
print (maxProfit( 0 , N, cost, profit, K, M))
|
C#
using System;
using System.Collections;
using System.Collections.Generic;
public class GFG {
static int [, , ] dp = new int [1001, 501, 11];
public static int maxProfit( int i, int N, int [] cost,
int [] profit, int K, int M)
{
if (i == N) {
return 0;
}
if (dp[M, i, K] != -1) {
return dp[M, i, K];
}
int ans1 = maxProfit(i + 1, N, cost, profit, K, M);
int ans2 = Int32.MinValue;
int ans3 = Int32.MinValue;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost, profit, K,
M - cost[i]);
}
if (K > 0) {
int newcost = cost[i] / 2;
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return dp[M, i, K]
= Math.Max(ans1, Math.Max(ans2, ans3));
}
public static void Main( string [] args)
{
int N = 3;
int [] cost = { 2, 4, 5 };
int [] profit = { 20, 17, 15 };
int K = 1;
int M = 4;
for ( int i = 0; i < 1001; i++) {
for ( int j = 0; j < 501; j++) {
for ( int k = 0; k < 11; k++) {
dp[i, j, k] = -1;
}
}
}
Console.WriteLine(
maxProfit(0, N, cost, profit, K, M));
}
}
|
Javascript
let dp = Array(1001).fill().map(e => Array(501).fill().map(e => Array(11).fill(-1).map(e => e)));
function maxProfit(i, N, cost, profit, K, M)
{
if (i == N) {
return 0;
}
if (dp[M][i][K] != -1) {
return dp[M][i][K];
}
let ans1 = maxProfit(i + 1, N, cost, profit, K, M);
let ans2 = Number.MIN_SAFE_INTEGER;
let ans3 = Number.MIN_SAFE_INTEGER;
if (M >= cost[i]) {
ans2 = profit[i]
+ maxProfit(i + 1, N, cost, profit, K,
M - cost[i]);
}
if (K > 0) {
let newcost = Math.floor(cost[i] / 2);
if (M >= newcost) {
ans3 = profit[i]
+ maxProfit(i + 1, N, cost, profit,
K - 1, M - newcost);
}
}
return dp[M][i][K] = Math.max(ans1, Math.max(ans2, ans3));
}
let N = 3;
let cost = [ 2, 4, 5 ];
let profit = [ 20, 17, 15 ];
let K = 1;
let M = 4;
for (let i = 0; i < 1001; i++) {
for (let j = 0; j < 501; j++) {
for (let k = 0; k < 11; k++) {
dp[i][j][k] = -1;
}
}
}
console.log(maxProfit(0, N, cost, profit, K, M));
|
Time Complexity: O(N*M*K)
Auxiliary Space: O(N*M*K)
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.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
int maxProfit( int N, int K, int M, int cost[], int profit[]) {
int dp[M+1][K+1][N+1];
for ( int i = 0; i <= M; i++) {
for ( int j = 0; j <= K; j++) {
for ( int k = 0; k <= N; k++) {
if (i == 0 || j == 0) {
dp[i][j][k] = 0;
} else {
dp[i][j][k] = -1;
}
}
}
}
for ( int i = N-1; i >= 0; i--) {
for ( int j = 0; j <= K; j++) {
for ( int k = 0; k <= M; k++) {
int ans1 = dp[k][j][i+1];
int ans2 = INT_MIN;
int ans3 = INT_MIN;
if (k >= cost[i]) {
ans2 = profit[i] + dp[k-cost[i]][j][i+1];
}
if (j > 0 && cost[i]/2 <= k) {
ans3 = profit[i] + dp[k-cost[i]/2][j-1][i+1];
}
dp[k][j][i] = max(ans1, max(ans2, ans3));
}
}
}
return dp[M][K][0];
}
int main() {
int N = 3;
int cost[3] = {2, 4, 5};
int profit[3] = {20, 17, 15};
int K = 1;
int M = 4;
cout << maxProfit(N, K, M, cost, profit) << endl;
return 0;
}
|
Java
import java.io.*;
class GFG {
static int maxProfit( int N, int K, int M, int cost[],
int profit[])
{
int [][][] dp = new int [M + 1 ][K + 1 ][N + 1 ];
for ( int i = 0 ; i <= M; i++) {
for ( int j = 0 ; j <= K; j++) {
for ( int k = 0 ; k <= N; k++) {
if (i == 0 || j == 0 ) {
dp[i][j][k] = 0 ;
}
else {
dp[i][j][k] = - 1 ;
}
}
}
}
for ( int i = N - 1 ; i >= 0 ; i--) {
for ( int j = 0 ; j <= K; j++) {
for ( int k = 0 ; k <= M; k++) {
int ans1 = dp[k][j][i + 1 ];
int ans2 = Integer.MIN_VALUE;
int ans3 = Integer.MIN_VALUE;
if (k >= cost[i]) {
ans2 = profit[i]
+ dp[k - cost[i]][j][i + 1 ];
}
if (j > 0 && cost[i] / 2 <= k) {
ans3 = profit[i]
+ dp[k - cost[i] / 2 ][j - 1 ]
[i + 1 ];
}
dp[k][j][i] = Math.max(
ans1, Math.max(ans2, ans3));
}
}
}
return dp[M][K][ 0 ];
}
public static void main(String[] args)
{
int N = 3 ;
int cost[] = { 2 , 4 , 5 };
int profit[] = { 20 , 17 , 15 };
int K = 1 ;
int M = 4 ;
System.out.println(
maxProfit(N, K, M, cost, profit));
}
}
|
Python3
def maxProfit(N, K, M, cost, profit):
dp = [[[ 0 for _ in range (N + 1 )] for _ in range (K + 1 )] for _ in range (M + 1 )]
for i in range (M + 1 ):
for j in range (K + 1 ):
for k in range (N + 1 ):
if i = = 0 or j = = 0 :
dp[i][j][k] = 0
else :
dp[i][j][k] = - 1
for i in range (N - 1 , - 1 , - 1 ):
for j in range (K + 1 ):
for k in range (M + 1 ):
ans1 = dp[k][j][i + 1 ]
ans2 = float ( '-inf' )
ans3 = float ( '-inf' )
if k > = cost[i]:
ans2 = profit[i] + dp[k - cost[i]][j][i + 1 ]
if j > 0 and cost[i] / / 2 < = k:
ans3 = profit[i] + dp[k - cost[i] / / 2 ][j - 1 ][i + 1 ]
dp[k][j][i] = max (ans1, max (ans2, ans3))
return dp[M][K][ 0 ]
N = 3
cost = [ 2 , 4 , 5 ]
profit = [ 20 , 17 , 15 ]
K = 1
M = 4
print (maxProfit(N, K, M, cost, profit))
|
C#
using System;
public class GFG {
public static int MaxProfit( int N, int K, int M,
int [] cost, int [] profit)
{
int [, , ] dp
= new int [M + 1, K + 1,
N + 1];
for ( int i = 0; i <= M; i++) {
for ( int j = 0; j <= K; j++) {
for ( int k = 0; k <= N; k++) {
if (i == 0 || j == 0) {
dp[i, j, k] = 0;
}
else {
dp[i, j, k] = -1;
}
}
}
}
for ( int i = N - 1; i >= 0; i--) {
for ( int j = 0; j <= K; j++) {
for ( int k = 0; k <= M; k++) {
int ans1
= dp[k, j, i + 1];
int ans2 = int .MinValue;
int ans3 = int .MinValue;
if (k >= cost[i]) {
ans2 = profit[i]
+ dp[k - cost[i], j, i + 1];
}
if (j > 0 && cost[i] / 2 <= k) {
ans3 = profit[i]
+ dp[k - cost[i] / 2, j - 1,
i + 1];
}
dp[k, j, i] = Math.Max(
ans1, Math.Max(ans2, ans3));
}
}
}
return dp[M, K, 0];
}
public static void Main( string [] args)
{
int N = 3;
int [] cost = { 2, 4, 5 };
int [] profit = { 20, 17, 15 };
int K = 1;
int M = 4;
Console.WriteLine(MaxProfit(N, K, M, cost, profit));
}
}
|
Javascript
function maxProfit(N, K, M, cost, profit) {
const dp = new Array(M + 1);
for (let i = 0; i <= M; i++) {
dp[i] = new Array(K + 1);
for (let j = 0; j <= K; j++) {
dp[i][j] = new Array(N + 1).fill(0);
}
}
for (let i = N - 1; i >= 0; i--) {
for (let j = 0; j <= K; j++) {
for (let k = 0; k <= M; k++) {
const ans1 = dp[k][j][i + 1];
let ans2 = -Infinity;
let ans3 = -Infinity;
if (k >= cost[i]) {
ans2 = profit[i] + dp[k - cost[i]][j][i + 1];
}
if (j > 0 && cost[i] / 2 <= k) {
ans3 = profit[i] + dp[k - Math.floor(cost[i] / 2)][j - 1][i + 1];
}
dp[k][j][i] = Math.max(ans1, ans2, ans3);
}
}
}
return dp[M][K][0];
}
const N = 3;
const cost = [2, 4, 5];
const profit = [20, 17, 15];
const K = 1;
const M = 4;
console.log(maxProfit(N, K, M, cost, profit));
|
Time Complexity: O(N*M*K)
Auxiliary Space: O(N*M*K)
Related articles:
Share your thoughts in the comments
Please Login to comment...