Open In App

Maximum profit

Last Updated : 24 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given N different tasks to be completed where the ith task belongs to a certain category, denoted by category[i], and has an associated reward represented by reward[i].

The objective is to determine the optimal order in which to complete these tasks to maximize the total reward. The reward obtained for completing a task is calculated as the product of the reward for that task and the number of distinct categories of tasks completed before (including the current task’s category).

Find the maximum possible total reward that can be achieved by strategically ordering the completion of tasks.

Examples:

Input: N = 4, category = [3, 1, 2, 3] and reward = [2, 1, 4, 4]
Output: 29
Explanation: For the given input, the optimal order of completion is as follows:

  • Complete the 2nd task: category[2] = 1, reward[2] = 1, number of distinct categories completed = 1, resulting in a profit of 1 x 1 = 1.
  • Complete the 1st task: category[1] = 3, reward[1] = 2, number of distinct categories completed = 2, resulting in a profit of 2 x 2 = 4.
  • Complete the 3rd task: category[3] = 2, reward[3] = 4, number of distinct categories completed = 3, resulting in a profit of 4 x 3 = 12.
  • Complete the 4th task: category[4] = 3, reward[4] = 4, number of distinct categories completed = 3, resulting in a profit of 4 x 3 = 12.

Therefore, the total profit is 1 + 4 + 12 + 12 = 29.

Input: N = 6, category = [2, 2, 2, 1, 3, 3], reward = [1, 2, 6, 4, 3, 5]
Output: 58
Explanation: For the given input, the optimal order of completion is as follows:

  • Complete the 1st task: category[1] = 2, reward[1] = 1, number of distinct categories completed = 1, resulting in a profit of 1 x 1 = 1.
  • Complete the 5th task: category[5] = 3, reward[5] = 3, number of distinct categories completed = 2, resulting in a profit of 2 x 3 = 6.
  • Complete the 4th task: category[4] = 1, reward[4] = 4, number of distinct categories completed = 3, resulting in a profit of 3 x 4 = 12.
  • Complete the 2nd task: category[2] = 2, reward[2] = 2, number of distinct categories completed = 3, resulting in a profit of 3 x 2 = 6.
  • Complete the 6th task: category[6] = 3, reward[6] = 5, number of distinct categories completed = 3, resulting in a profit of 3 x 5 = 15.
  • Complete the 3rd task: category[3] = 2, reward[3] = 6, number of distinct categories completed = 3, resulting in a profit of 3 x 6 = 18.

Therefore, the total profit is 1 + 6 + 12 + 6 + 15 + 18 = 58.

Approach: To solve the problem, follow the below idea:

The problem can be solved by taking one task with minimum reward from each category and perform them in increasing order of their reward. For the remaining tasks, they can be performed in any order as all the categories would have been covered earlier.

Step-by-step algorithm:

  • Initialize two maps: categorySumOfRewards to store the sum of rewards for each task category, and categoryMinimumReward to store the minimum reward for each task category.
  • Iterate through the tasks, updating the maps based on the task category and reward.
  • Create a vector minRewards to store the minimum rewards for each category and initialize maxTotalReward to 0.
  • Iterate through categorySumOfRewards, calculate the contribution to maxTotalReward for each category by subtracting the minimum reward and multiplying it by the count of distinct categories completed before.
  • Sort minRewards in ascending order.
  • Iterate through minRewards, adding additional rewards to maxTotalReward based on the sorted minimum rewards.
  • Return maxTotalReward as the maximum possible total reward.

Below is the implementation of the approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
// Function to find the maximum total reward from
// strategically ordering the completion of tasks
long findMaximumTotalReward(vector<int>& taskCategories,
                            vector<int>& taskRewards)
{
    // Maps to store the sum of rewards and minimum reward
    // for each task category
    map<int, long long> categorySumOfRewards;
    map<int, int> categoryMinimumReward;
 
    int n = taskCategories.size();
 
    // Calculate the sum of rewards and minimum reward for
    // each task category
    for (int i = 0; i < n; i++) {
        // Update sum of rewards for the task category
        if (!categorySumOfRewards.count(taskCategories[i])) {
            categorySumOfRewards.insert({ taskCategories[i], 0 });
        }
        categorySumOfRewards[taskCategories[i]]
            += taskRewards[i];
 
        // Update minimum reward for the task category
        if (!categoryMinimumReward.count(
                taskCategories[i])) {
            categoryMinimumReward.insert(
                { taskCategories[i], INT_MAX });
        }
        categoryMinimumReward[taskCategories[i]]
            = min(categoryMinimumReward[taskCategories[i]],
                taskRewards[i]);
    }
 
    vector<int> minRewards;
    long long maxTotalReward = 0LL;
    int categoryCount = categoryMinimumReward.size();
 
    // Calculate maximum total reward using accumulated sum
    // of rewards and minimum rewards
    for (auto it = categorySumOfRewards.begin();
        it != categorySumOfRewards.end(); ++it) {
        int taskCategory = it->first;
        long long sum = it->second;
 
        maxTotalReward += (long long)
        (sum - categoryMinimumReward[taskCategory])
            * (categoryCount);
        minRewards.push_back(
            categoryMinimumReward[taskCategory]);
    }
 
    // Sort the minimum rewards in ascending order
    sort(minRewards.begin(), minRewards.end());
 
    // Calculate additional reward based on the sorted
    // minimum rewards
    for (int i = 0; i < minRewards.size(); i++) {
        maxTotalReward
            += (long long)minRewards[i] * (i + 1);
    }
 
    return (long)maxTotalReward;
}
 
int main()
{
    // Test case
    vector<int> taskCategories = { 3, 1, 2, 3 };
    vector<int> taskRewards = { 2, 1, 4, 4 };
 
    // Output the maximum total reward
    cout << "Max Total Rewards: "
        << findMaximumTotalReward(taskCategories,
                                taskRewards)
        << endl;
 
    return 0;
}


Java




import java.util.*;
 
public class Main {
 
    // Function to find the maximum total reward from
    // strategically ordering the completion of tasks
    static long findMaximumTotalReward(ArrayList<Integer> taskCategories, ArrayList<Integer> taskRewards) {
        // Maps to store the sum of rewards and minimum reward
        // for each task category
        HashMap<Integer, Long> categorySumOfRewards = new HashMap<>();
        HashMap<Integer, Integer> categoryMinimumReward = new HashMap<>();
 
        int n = taskCategories.size();
 
        // Calculate the sum of rewards and minimum reward for
        // each task category
        for (int i = 0; i < n; i++) {
            // Update sum of rewards for the task category
            categorySumOfRewards.put(taskCategories.get(i), categorySumOfRewards.getOrDefault(taskCategories.get(i), 0L) + taskRewards.get(i));
 
            // Update minimum reward for the task category
            categoryMinimumReward.put(taskCategories.get(i), Math.min(categoryMinimumReward.getOrDefault(taskCategories.get(i), Integer.MAX_VALUE), taskRewards.get(i)));
        }
 
        ArrayList<Integer> minRewards = new ArrayList<>();
        long maxTotalReward = 0L;
        int categoryCount = categoryMinimumReward.size();
 
        // Calculate maximum total reward using accumulated sum
        // of rewards and minimum rewards
        for (Map.Entry<Integer, Long> entry : categorySumOfRewards.entrySet()) {
            int taskCategory = entry.getKey();
            long sum = entry.getValue();
 
            maxTotalReward += (sum - categoryMinimumReward.get(taskCategory)) * categoryCount;
            minRewards.add(categoryMinimumReward.get(taskCategory));
        }
 
        // Sort the minimum rewards in ascending order
        Collections.sort(minRewards);
 
        // Calculate additional reward based on the sorted
        // minimum rewards
        for (int i = 0; i < minRewards.size(); i++) {
            maxTotalReward += minRewards.get(i) * (i + 1);
        }
 
        return maxTotalReward;
    }
 
    public static void main(String[] args) {
        // Test case
        ArrayList<Integer> taskCategories = new ArrayList<>(Arrays.asList(3, 1, 2, 3));
        ArrayList<Integer> taskRewards = new ArrayList<>(Arrays.asList(2, 1, 4, 4));
 
        // Output the maximum total reward
        System.out.println("Max Total Rewards: " + findMaximumTotalReward(taskCategories, taskRewards));
    }
}
 
// This code is contributed by rambabuguphka


Python3




def find_maximum_total_reward(task_categories, task_rewards):
    # Dictionary to store the sum of rewards and minimum reward
    # for each task category
    category_sum_of_rewards = {}
    category_minimum_reward = {}
 
    n = len(task_categories)
 
    # Calculate the sum of rewards and minimum reward for
    # each task category
    for i in range(n):
        # Update sum of rewards for the task category
        if task_categories[i] not in category_sum_of_rewards:
            category_sum_of_rewards[task_categories[i]] = 0
        category_sum_of_rewards[task_categories[i]] += task_rewards[i]
 
        # Update minimum reward for the task category
        if task_categories[i] not in category_minimum_reward:
            category_minimum_reward[task_categories[i]] = float('inf')
        category_minimum_reward[task_categories[i]] = min(
            category_minimum_reward[task_categories[i]],
            task_rewards[i]
        )
 
    min_rewards = []
    max_total_reward = 0
 
    # Calculate maximum total reward using accumulated sum
    # of rewards and minimum rewards
    for task_category, reward_sum in category_sum_of_rewards.items():
        sum_rewards = reward_sum
        max_total_reward += (sum_rewards -
                             category_minimum_reward[task_category]) * len(category_minimum_reward)
 
        min_rewards.append(category_minimum_reward[task_category])
 
    # Sort the minimum rewards in ascending order
    min_rewards.sort()
 
    # Calculate additional reward based on the sorted
    # minimum rewards
    for i in range(len(min_rewards)):
        max_total_reward += min_rewards[i] * (i + 1)
 
    return max_total_reward
 
 
# Test case
task_categories = [3, 1, 2, 3]
task_rewards = [2, 1, 4, 4]
 
# Output the maximum total reward
print("Max Total Rewards:", find_maximum_total_reward(task_categories, task_rewards))


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    // Function to find the maximum total reward from
    // strategically ordering the completion of tasks
    static long FindMaximumTotalReward(List<int> taskCategories, List<int> taskRewards)
    {
        // Dictionaries to store the sum of rewards and minimum reward
        // for each task category
        Dictionary<int, long> categorySumOfRewards = new Dictionary<int, long>();
        Dictionary<int, int> categoryMinimumReward = new Dictionary<int, int>();
 
        int n = taskCategories.Count;
 
        // Calculate the sum of rewards and minimum reward for
        // each task category
        for (int i = 0; i < n; i++)
        {
            // Update sum of rewards for the task category
            if (!categorySumOfRewards.ContainsKey(taskCategories[i]))
            {
                categorySumOfRewards[taskCategories[i]] = 0;
            }
            categorySumOfRewards[taskCategories[i]] += taskRewards[i];
 
            // Update minimum reward for the task category
            if (!categoryMinimumReward.ContainsKey(taskCategories[i]))
            {
                categoryMinimumReward[taskCategories[i]] = int.MaxValue;
            }
            categoryMinimumReward[taskCategories[i]] = Math.Min(categoryMinimumReward[taskCategories[i]], taskRewards[i]);
        }
 
        List<int> minRewards = new List<int>();
        long maxTotalReward = 0;
 
        int categoryCount = categoryMinimumReward.Count;
 
        // Calculate maximum total reward using accumulated sum
        // of rewards and minimum rewards
        foreach (var entry in categorySumOfRewards)
        {
            int taskCategory = entry.Key;
            long sum = entry.Value;
 
            maxTotalReward += (sum - categoryMinimumReward[taskCategory]) * categoryCount;
            minRewards.Add(categoryMinimumReward[taskCategory]);
        }
 
        // Sort the minimum rewards in ascending order
        minRewards.Sort();
 
        // Calculate additional reward based on the sorted
        // minimum rewards
        for (int i = 0; i < minRewards.Count; i++)
        {
            maxTotalReward += minRewards[i] * (i + 1);
        }
 
        return maxTotalReward;
    }
 
    static void Main(string[] args)
    {
        // Test case
        List<int> taskCategories = new List<int> { 3, 1, 2, 3 };
        List<int> taskRewards = new List<int> { 2, 1, 4, 4 };
 
        // Output the maximum total reward
        Console.WriteLine("Max Total Rewards: " + FindMaximumTotalReward(taskCategories, taskRewards));
    }
}


Javascript




// Function to find the maximum total reward from strategically ordering the completion of tasks
function findMaximumTotalReward(taskCategories, taskRewards) {
    // Maps to store the sum of rewards and minimum reward for each task category
    let categorySumOfRewards = {};
    let categoryMinimumReward = {};
 
    let n = taskCategories.length;
 
    // Calculate the sum of rewards and minimum reward for each task category
    for (let i = 0; i < n; i++) {
        // Update sum of rewards for the task category
        if (!categorySumOfRewards.hasOwnProperty(taskCategories[i])) {
            categorySumOfRewards[taskCategories[i]] = 0;
        }
        categorySumOfRewards[taskCategories[i]] += taskRewards[i];
 
        // Update minimum reward for the task category
        if (!categoryMinimumReward.hasOwnProperty(taskCategories[i])) {
            categoryMinimumReward[taskCategories[i]] = Number.MAX_SAFE_INTEGER;
        }
        categoryMinimumReward[taskCategories[i]] = Math.min(categoryMinimumReward[taskCategories[i]], taskRewards[i]);
    }
 
    let minRewards = [];
    let maxTotalReward = 0;
    let categoryCount = Object.keys(categoryMinimumReward).length;
 
    // Calculate maximum total reward using accumulated sum of rewards and minimum rewards
    for (let taskCategory in categorySumOfRewards) {
        let sum = categorySumOfRewards[taskCategory];
 
        maxTotalReward += (sum - categoryMinimumReward[taskCategory]) * categoryCount;
        minRewards.push(categoryMinimumReward[taskCategory]);
    }
 
    // Sort the minimum rewards in ascending order
    minRewards.sort((a, b) => a - b);
 
    // Calculate additional reward based on the sorted minimum rewards
    for (let i = 0; i < minRewards.length; i++) {
        maxTotalReward += minRewards[i] * (i + 1);
    }
 
    return maxTotalReward;
}
 
// Test case
let taskCategories = [3, 1, 2, 3];
let taskRewards = [2, 1, 4, 4];
 
// Output the maximum total reward
console.log("Max Total Rewards: " + findMaximumTotalReward(taskCategories, taskRewards));


Output

Max Total Rewards: 29



Time Complexity: O(N * log N), where N is the number of tasks.
Auxiliary Space: O(C), where C is the number of distinct task categories.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads