Given two machines, Machine A and Machine B, and a set of n tasks. The profit earned for performing each task is given in two arrays a[] and b[] such that if Machine A performs the i-th task, the profit is a[i], and if Machine B performs it, the profit is b[i].
Machine A can process at most x tasks, and Machine B can process at most y tasks. It is guaranteed that x + y ≥ n, so all tasks can be assigned. Return the maximum possible profit after assigning each task to either Machine A or Machine B.
Examples:
Input: x = 3, y = 3, a[] = {1, 2, 3, 4, 5}, b[] = {5, 4, 3, 2, 1}
Output: 21
Explanation: Machine A will process the 3, 4 and 5 tasks while Machine B will process the rest so the total profit from A = 3 + 4 + 5 and B = 5 + 4 i.e. 21.Input: x = 3, y = 4, a[] = {8, 7, 15, 19, 16, 16, 18}, b[] = {1, 7, 15, 11, 12, 31, 9}
Output: 110
Explanation: Machine A will process tasks 8, 19, 18 while Machine B will process tasks 7, 15, 12 and 31.
Table of Content
[Naive Approach] - Using Recursion - O(2^n) Time and O(1) Space
The simplest approach is to use recursion because for each task, we have two choices: assign it to Machine A or Machine B. We recursively try both options and pick the one that maximizes the total profit, while ensuring that neither A nor B exceeds their order limits. As in every step, there is a choice to be made, this is similar to the 0-1 Knapsack Problem, in which decisions are made whether to include or exclude an element.
Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
// Helper function for finding maximum profit
int maxProfitUtil(int i, int x, int y, vector<int> &a, vector<int> &b)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0)
{
// Option 1: Assign current task to Machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// Option 2: Assign current task to Machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
// Choose maximum of both
return max(takeA, takeB);
}
// If only Machine A can process tasks that means Machine B exhausted
if (y == 0)
{
return a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
}
// If only Machine B can process tasks that means Machine A exhausted
return b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
}
// Function to calculate maximum profit using recursion
int maxProfit(int x, int y, vector<int> &a, vector<int> &b)
{
int n = a.size();
return maxProfitUtil(n - 1, x, y, a, b);
}
int main()
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {5, 4, 3, 2, 1};
cout << maxProfit(x, y, a, b);
return 0;
}
import java.util.*;
public class GFG {
// Helper function for finding maximum profit
static int maxProfitUtil(int i, int x, int y, int[] a,
int[] b)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// Option 2: Assign current task to machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
// Choose maximum of both
return Math.max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
if (y == 0) {
return a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
}
// If only machine B can process tasks that means machine A exhausted
return b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
}
// Function to calculate maximum profit using recursion
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.length;
return maxProfitUtil(n - 1, x, y, a, b);
}
public static void main(String[] args)
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
System.out.println(maxProfit(x, y, a, b));
}
}
# Helper function for finding maximum profit
def maxProfitUtil(i, x, y, a, b):
# Base Case: No tasks left
if i < 0:
return 0
# If both machine A and machine B can process tasks
if x > 0 and y > 0:
# Option 1: Assign current task to machine A
takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b)
# Option 2: Assign current task to machine B
takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b)
# Choose maximum of both
return max(takeA, takeB)
# If only machine A can process tasks that means machine B exhausted
if y == 0:
return a[i] + maxProfitUtil(i - 1, x - 1, y, a, b)
# If only machine B can process tasks that means machine A exhausted
return b[i] + maxProfitUtil(i - 1, x, y - 1, a, b)
# Function to calculate maximum profit using recursion
def maxProfit(x, y, a, b):
n = len(a)
return maxProfitUtil(n - 1, x, y, a, b)
# Driver Code
x = 3 # max tasks machine A can process
y = 3 # max tasks machine B can process
a = [1, 2, 3, 4, 5]
b = [5, 4, 3, 2, 1]
print(maxProfit(x, y, a, b))
using System;
class GFG {
// Helper function for finding maximum profit
static int maxProfitUtil(int i, int x, int y, int[] a,
int[] b)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// Option 2: Assign current task to machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
// Choose maximum of both
return Math.Max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
if (y == 0)
return a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// If only machine B can process tasks that means machine A exhausted
return b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
}
// Function to calculate maximum profit using recursion
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.Length;
return maxProfitUtil(n - 1, x, y, a, b);
}
static void Main()
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
Console.WriteLine(maxProfit(x, y, a, b));
}
}
// Helper function for finding maximum profit
function maxProfitUtil(i, x, y, a, b) {
// Base Case: No tasks left
if (i < 0)
return 0;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
let takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// Option 2: Assign current task to machine B
let takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
// Choose maximum of both
return Math.max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
if (y === 0)
return a[i] + maxProfitUtil(i - 1, x - 1, y, a, b);
// If only machine B can process tasks that means machine A exhausted
return b[i] + maxProfitUtil(i - 1, x, y - 1, a, b);
}
// Function to calculate maximum profit using recursion
function maxProfit(x, y, a, b) {
let n = a.length;
return maxProfitUtil(n - 1, x, y, a, b);
}
// Driver Code
let x = 3; // max tasks machine A can process
let y = 3; // max tasks machine B can process
let a = [1, 2, 3, 4, 5];
let b = [5, 4, 3, 2, 1];
console.log(maxProfit(x, y, a, b));
Output
21
[Better Approach] - Using Top Down DP - O(n*x*y) time and O(n*x*y) space
The above approach can be optimized by using Dynamic Programming and Memoization. The recursive solution has overlapping subproblems because the same state (i, x, y) is computed multiple times. We can store the result of each state in a DP table and reuse it, reducing time complexity from exponential to polynomial.

Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
// Helper function for finding maximum profit
int maxProfitUtil(int i, int x, int y, vector<int> &a, vector<int> &b, unordered_map<string, int> &dp)
{
// Base Case: No tasks left
if (i < 0)
return 0;
string key = to_string(i) + "_" + to_string(x) + "_" + to_string(y);
// checking if this state is already visited
if (dp.find(key) != dp.end())
{
return dp[key];
}
// If both machine A and machine B can process tasks
if (x > 0 && y > 0)
{
// Option 1: Assign current task to machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
// Option 2: Assign current task to machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
// Choose maximum of both
return dp[key] = max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
if (y == 0)
{
return dp[key] = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
}
// If only machine B can process tasks that means machine A exhausted
return dp[key] = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
}
// Function to calculate maximum profit using recursion
int maxProfit(int x, int y, vector<int> &a, vector<int> &b)
{
int n = a.size();
// initialized a map to store recursive states
unordered_map<string, int> dp;
return maxProfitUtil(n - 1, x, y, a, b, dp);
}
int main()
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {5, 4, 3, 2, 1};
cout << maxProfit(x, y, a, b);
return 0;
}
import java.util.*;
public class GFG {
// Helper function for finding maximum profit
static int maxProfitUtil(int i, int x, int y, int[] a,
int[] b,
HashMap<String, Integer> dp)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// Create unique key for current state
String key = i + "_" + x + "_" + y;
// Check if already computed
if (dp.containsKey(key))
return dp.get(key);
int result;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
// Option 2: Assign current task to machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
// Choose maximum of both
result = Math.max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
else if (y == 0) {
result = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
}
else {
// If only machine B can process tasks that means machine A
// exhausted
result = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
}
// Store result in map
dp.put(key, result);
return result;
}
// Function to calculate maximum profit using recursion
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.length;
// HashMap for memoization
HashMap<String, Integer> dp = new HashMap<>();
return maxProfitUtil(n - 1, x, y, a, b, dp);
}
public static void main(String[] args)
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
System.out.println(maxProfit(x, y, a, b));
}
}
# Helper function for finding maximum profit
def maxProfitUtil(i, x, y, a, b, dp):
# Base Case: No tasks left
if i < 0:
return 0
# Create key for current state
key = (i, x, y)
# Check if already computed
if key in dp:
return dp[key]
# If both machine A and machine B can process tasks
if x > 0 and y > 0:
# Option 1: Assign current task to machine A
takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp)
# Option 2: Assign current task to machine B
takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp)
# Choose maximum of both
dp[key] = max(takeA, takeB)
return dp[key]
# If only machine A can process tasks that means machine B exhausted
elif y == 0:
dp[key] = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp)
return dp[key]
# If only machine B can process tasks that means machine A exhausted
else:
dp[key] = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp)
return dp[key]
# Function to calculate maximum profit using recursion
def maxProfit(x, y, a, b):
n = len(a)
# Dictionary for memoization
dp = {}
return maxProfitUtil(n - 1, x, y, a, b, dp)
# Driver Code
x = 3 # max tasks machine A can process
y = 3 # max tasks machine B can process
a = [1, 2, 3, 4, 5]
b = [5, 4, 3, 2, 1]
print(maxProfit(x, y, a, b))
using System;
using System.Collections.Generic;
class GFG {
// Helper function for finding maximum profit
static int maxProfitUtil(int i, int x, int y, int[] a,
int[] b, Dictionary<string, int> dp)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// Create unique key for state
string key = i + "_" + x + "_" + y;
// Check if already computed
if (dp.ContainsKey(key))
return dp[key];
int result;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
int takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
// Option 2: Assign current task to machine B
int takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
// Choose maximum of both
result = Math.Max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
else if (y == 0)
result = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
// If only machine B can process tasks that means machine A exhausted
else
result = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
// Store result
dp[key] = result;
return result;
}
// Function to calculate maximum profit using recursion
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.Length;
// Dictionary for memoization
Dictionary<string, int> dp = new Dictionary<string, int>();
return maxProfitUtil(n - 1, x, y, a, b, dp);
}
static void Main()
{
int x = 3; // max tasks machine A can process
int y = 3; // max tasks machine B can process
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
Console.WriteLine(maxProfit(x, y, a, b));
}
}
// Helper function for finding maximum profit
function maxProfitUtil(i, x, y, a, b, dp)
{
// Base Case: No tasks left
if (i < 0)
return 0;
// Create unique key for state
let key = i + "_" + x + "_" + y;
// Check if already computed
if (dp.has(key))
return dp.get(key);
let result;
// If both machine A and machine B can process tasks
if (x > 0 && y > 0) {
// Option 1: Assign current task to machine A
let takeA = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
// Option 2: Assign current task to machine B
let takeB = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
// Choose maximum of both
result = Math.max(takeA, takeB);
}
// If only machine A can process tasks that means machine B exhausted
else if (y === 0){
result = a[i] + maxProfitUtil(i - 1, x - 1, y, a, b, dp);
}
// If only machine B can process tasks that means machine A exhausted
else {
result = b[i] + maxProfitUtil(i - 1, x, y - 1, a, b, dp);
}
// Store result in map
dp.set(key, result);
return result;
}
// Function to calculate maximum profit using recursion
function maxProfit(x, y, a, b)
{
let n = a.length;
// Map for memoization
let dp = new Map();
return maxProfitUtil(n - 1, x, y, a, b, dp);
}
// Driver Code
let x = 3; // max tasks machine A can process
let y = 3; // max tasks machine B can process
let a = [ 1, 2, 3, 4, 5 ];
let b = [ 5, 4, 3, 2, 1 ];
console.log(maxProfit(x, y, a, b));
Output
21
[Expected Approach] - Using Greedy Method - O(n * log n) time and O(n) space
The idea is that we should first handle the tasks where the difference between profits is highest, because choosing the wrong machine for those tasks would cause the biggest loss. For tasks where both machines give similar profits, it doesn’t matter much who processes them. So, we greedily assign each task to the machine who gives higher profit while respecting constraints.
Dry run for the above example: a = {1, 2, 3}, b = {5, 4, 2}, x = 2, y = 1
- Build difference array: (diff, index)
i = 0 --> |1 - 5| = 4 --> (4, 0)
i = 1 --> |2 - 4| = 2 --> (2, 1)
i = 2 --> |3 - 2| = 1 --> (1, 2) - Sort (descending) based on diff: [(4, 0), (2, 1), (1, 2)]
- For i = 0 --> (a[0] = 1 < b[0] = 5) --> take Machine B --> ans = 5, x = 2, y = 0
- For i = 1 --> (y = 0, so must take Machine A) --> ans = 7, x = 1, y = 0
- For i = 2 --> (y = 0, so must take Machine A) --> ans = 10, x = 0, y = 0
Final answer: maximum profit = 10
#include <bits/stdc++.h>
using namespace std;
int maxProfit(int x, int y, vector<int> &a, vector<int> &b)
{
int n = a.size();
// Create an array of absolute differences
vector<vector<int>> diff(n, vector<int>(2));
for (int i = 0; i < n; i++)
{
diff[i] = {abs(a[i] - b[i]), i};
}
// Sort the difference array in descending
// order of differences in order to maximize profits
sort(diff.begin(), diff.end(), greater<vector<int>>());
int ans = 0;
int i = 0;
// While x and y are greater than 0, pick
// the task with greater profit.
while (i < n && x > 0 && y > 0)
{
int index = diff[i][1];
if (a[index] >= b[index])
{
ans += a[index];
x--;
}
else
{
ans += b[index];
y--;
}
i++;
}
// If machine B has already done maximum tasks,
// rest of the tasks will be done by machine A.
while (i < n && x > 0)
{
int index = diff[i][1];
ans += a[index];
x--;
i++;
}
// If machine A has already done maximum tasks,
// rest of the tasks will be done by machine B.
while (i < n && y > 0)
{
int index = diff[i][1];
ans += b[index];
y--;
i++;
}
return ans;
}
int main()
{
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {5, 4, 3, 2, 1};
int x = 3, y = 3;
cout << maxProfit(x, y, a, b);
return 0;
}
import java.util.*;
class GfG {
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.length;
// Create an array of absolute differences
int[][] diff = new int[n][2];
for (int i = 0; i < n; i++) {
diff[i][0] = Math.abs(a[i] - b[i]);
diff[i][1] = i;
}
// Sort the difference array in descending
// order of differences in order to maximize
// profits
Arrays.sort(diff, (c, d) -> Integer.compare(d[0], c[0]));
int ans = 0;
int i = 0;
// While x and y are greater than 0, pick
// the task with greater profit.
while (i < n && x > 0 && y > 0) {
int index = diff[i][1];
if (a[index] >= b[index]) {
ans += a[index];
x--;
}
else {
ans += b[index];
y--;
}
i++;
}
// If machine B has already done maximum tasks,
// rest of the tasks will be done by machine A.
while (i < n && x > 0) {
int index = diff[i][1];
ans += a[index];
x--;
i++;
}
// If machine A has already done maximum tasks,
// rest of the tasks will be done by machine B.
while (i < n && y > 0) {
int index = diff[i][1];
ans += b[index];
y--;
i++;
}
return ans;
}
public static void main(String[] args)
{
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
int x = 3, y = 3;
System.out.println(maxProfit(x, y, a, b));
}
}
def maxProfit(x, y, a, b):
n = len(a)
# Create an array of absolute differences
diff = []
for i in range(n):
diff.append([abs(a[i]-b[i]), i])
# Sort the difference array in descending
# order of differences in order to maximize
# profits
diff.sort(reverse=True)
ans = 0
i = 0
# While x and y are greater than 0, pick
# the task with greater profit.
while i < n and x>0 and y>0:
index = diff[i][1]
if a[index] >= b[index]:
ans += a[index]
x -= 1
else:
ans += b[index]
y -= 1
i += 1
# If machine B has already done maximum tasks,
# rest of the tasks will be done by machine A.
while i < n and x > 0:
index = diff[i][1]
ans += a[index]
x -= 1
i += 1
# If machine A has already done maximum tasks,
# rest of the tasks will be done by machine B.
while i < n and y > 0:
index = diff[i][1]
ans += b[index]
y -= 1
i += 1
return ans
# Driver code
if __name__ == "__main__":
a = [1, 2, 3, 4, 5]
b = [5, 4, 3, 2, 1]
x = 3
y = 3
print(maxProfit(x, y, a, b))
using System;
using System.Linq;
class GfG {
static int maxProfit(int x, int y, int[] a, int[] b)
{
int n = a.Length;
// Create an array of absolute differences
int[][] diff = new int[n][];
for (int j = 0; j < n; j++) {
diff[j] = new int[2];
diff[j][0] = Math.Abs(a[j] - b[j]);
diff[j][1] = j;
}
// Sort the difference array in descending
// order of differences in order to maximize
// profits
Array.Sort(diff, (c, d) => d[0].CompareTo(c[0]));
int ans = 0;
int i = 0;
// While x and y are greater than 0, pick
// the task with greater profit.
while (i < n && x > 0 && y > 0) {
int index = diff[i][1];
if (a[index] >= b[index]) {
ans += a[index];
x--;
}
else {
ans += b[index];
y--;
}
i++;
}
// If machine B has already done maximum tasks,
// rest of the tasks will be done by machine A.
while (i < n && x > 0) {
int index = diff[i][1];
ans += a[index];
x--;
i++;
}
// If machine A has already done maximum tasks,
// rest of the tasks will be done by machine B.
while (i < n && y > 0) {
int index = diff[i][1];
ans += b[index];
y--;
i++;
}
return ans;
}
static void Main()
{
int[] a = { 1, 2, 3, 4, 5 };
int[] b = { 5, 4, 3, 2, 1 };
int x = 3, y = 3;
Console.WriteLine(maxProfit(x, y, a, b));
}
}
function maxProfit(x, y, a, b)
{
let n = a.length;
// Create an array of absolute differences
let diff = [];
for (let i = 0; i < n; i++) {
diff.push([ Math.abs(a[i] - b[i]), i ]);
}
// Sort the difference array in descending
// order of differences in order to maximize
// profits
diff.sort((a, b) => b[0] - a[0]);
let ans = 0;
let i = 0;
// While x and y are greater than 0, pick
// the task with greater profit.
while (i < n && x > 0 && y > 0) {
let index = diff[i][1];
if (a[index] >= b[index]) {
ans += a[index];
x--;
}
else {
ans += b[index];
y--;
}
i++;
}
// If machine B has already done maximum tasks,
// rest of the tasks will be done by machine A.
while (i < n && x > 0) {
let index = diff[i][1];
ans += a[index];
x--;
i++;
}
// If machine A has already done maximum tasks,
// rest of the tasks will be done by machine B.
while (i < n && y > 0) {
let index = diff[i][1];
ans += b[index];
y--;
i++;
}
return ans;
}
// Driver code
let a = [ 1, 2, 3, 4, 5 ];
let b = [ 5, 4, 3, 2, 1 ];
let x = 3, y = 3;
console.log(maxProfit(x, y, a, b));
Output
21