Open In App

Maximum Tip Calculator

Improve
Improve
Like Article
Like
Save
Share
Report

Rahul and Ankit are the only two waiters in Royal Restaurant. Today, the restaurant received N orders. The amount of tips may differ when handled by different waiters, if Rahul takes the ith order, he would be tipped Ai rupees and if Ankit takes this order, the tip would be Bi rupees. 
In order to maximize the total tip value they decided to distribute the order among themselves. One order will be handled by one person only. Also, due to time constraints, Rahul cannot take more than X orders and Ankit cannot take more than Y orders. It is guaranteed that X + Y is greater than or equal to N, which means that all the orders can be handled by either Rahul or Ankit. Find out the maximum possible amount of total tip money after processing all the orders.

Examples: 

Input: A[] = {1, 2, 3, 4, 5}, B[] = {5, 4, 3, 2, 1}, X = 3, Y = 3 
Output: 21 
1st, 2nd and 3rd orders are taken by waiter Y. 
4th and 5th orders are taken by waiter X.

Input: A[] = {2, 2, 2}, B[] = {3, 3, 3}, X = 3, Y = 3 
Output:

Recursive solution: We can move in a recursive way to calculate the maximum amount order to be taken in such a manner 
that the total tip would be maximum. The solution would contain 4 cases:  

  1. i == n: When this is reached it means all orders are taken. So return 0 and move back.
  2. X ? 0: When waiter X cannot take more orders.
  3. Y ? 0: When waiter Y cannot take more orders.
  4. max(Orders(X), Orders(Y)): We need to return the maximum of tip when orders taken by both X and Y.

Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
 
#include <bits/stdc++.h>
using namespace std;
int n;
 
// Recursive function to calculate sum of
// maximum tip order taken by X and Y
int solve(int i, int X, int Y,
          int a[], int b[], int n)
{
 
    // When all orders have been taken
    if (i == n)
        return 0;
 
    // When X cannot take more orders
    if (X <= 0)
        return b[i] + solve(i + 1, X,
                            Y - 1, a, b, n);
 
    // When Y cannot take more orders
    if (Y <= 0)
        return a[i] + solve(i + 1, X - 1,
                            Y, a, b, n);
 
    // When both can take order
    // calculate maximum out of two
    else
        return max(a[i] + solve(i + 1, X - 1,
                                Y, a, b, n),
                   b[i] + solve(i + 1, X,
                                Y - 1, a, b, n));
}
 
// Driver code
int main()
{
    int a[] = { 1, 2, 3, 4, 5 };
    int b[] = { 5, 4, 3, 2, 1 };
    int n = sizeof(a) / sizeof(a[0]);
    int x = 3, y = 3;
 
    cout << solve(0, x, y, a, b, n);
 
    return 0;
}


Java




// Java implementation for the above approach
import java.io.*;
 
class GFG
{
    static int n;
 
    // Recursive function to calculate sum of
    // maximum tip order taken by X and Y
    static int solve(int i, int X, int Y, int a[], int b[],
                     int n)
    {
 
        // When all orders have been taken
        if (i == n)
            return 0;
 
        // When X cannot take more orders
        if (X <= 0)
            return b[i] + solve(i + 1, X, Y - 1, a, b, n);
 
        // When Y cannot take more orders
        if (Y <= 0)
            return a[i] + solve(i + 1, X - 1, Y, a, b, n);
 
        // When both can take order
        // calculate maximum out of two
        else
            return Math.max(
                a[i] + solve(i + 1, X - 1, Y, a, b, n),
                b[i] + solve(i + 1, X, Y - 1, a, b, n));
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int a[] = { 1, 2, 3, 4, 5 };
        int b[] = { 5, 4, 3, 2, 1 };
        int n = a.length;
        int x = 3, y = 3;
 
        System.out.println(solve(0, x, y, a, b, n));
    }
}
 
// This code is contributed by Potta Lokesh


Python3




# Python3 program for the above approach
 
# Recursive function to calculate sum of
# maximum tip order taken by X and Y
def solve(i, X, Y,
          a, b, n) :
 
    # When all orders have been taken
    if (i == n):
        return 0
 
    # When X cannot take more orders
    if (X <= 0):
        return (b[i] + solve(i + 1, X,
                            Y - 1, a, b, n))
 
    # When Y cannot take more orders
    if (Y <= 0):
        return (a[i] + solve(i + 1, X - 1,
                            Y, a, b, n))
 
    # When both can take order
    # calculate maximum out of two
    else:
        return max(a[i] + solve(i + 1, X - 1,
                                Y, a, b, n),
                   b[i] + solve(i + 1, X,
                                Y - 1, a, b, n))
 
# Driver code
a = [ 1, 2, 3, 4, 5 ]
b = [ 5, 4, 3, 2, 1 ]
 
n = len(a)
 
x = 3
y = 3
 
print(solve(0, x, y, a, b, n))
 
# This code is contributed by splevel62.


C#




// C# program for the above approach
using System;
 
class GFG{
 
static int n;
 
// Recursive function to calculate sum of
// maximum tip order taken by X and Y
static int solve(int i, int X, int Y,
                 int[] a, int[] b, int n)
{
     
    // When all orders have been taken
    if (i == n)
        return 0;
 
    // When X cannot take more orders
    if (X <= 0)
        return b[i] + solve(i + 1, X, Y - 1,
                            a, b, n);
 
    // When Y cannot take more orders
    if (Y <= 0)
        return a[i] + solve(i + 1, X - 1, Y,
                            a, b, n);
 
    // When both can take order
    // calculate maximum out of two
    else
        return Math.Max(
            a[i] + solve(i + 1, X - 1, Y, a, b, n),
            b[i] + solve(i + 1, X, Y - 1, a, b, n));
}
 
// Driver Code
public static void Main(String[] args)
{
    int[] a = { 1, 2, 3, 4, 5 };
    int[] b = { 5, 4, 3, 2, 1 };
    // int n = a.Length;
    int x = 3, y = 3;
 
    Console.Write(solve(0, x, y, a, b, n));
}
}
 
// This code is contributed by sanjoy_62


Javascript




<script>
 
// JavaScript implementation of the approach
 
let n;
 
// Recursive function to calculate sum of
// maximum tip order taken by X and Y
function solve(i, X, Y, a, b, n) {
  // When all orders have been taken
  if (i == n) return 0;
 
  // When X cannot take more orders
  if (X <= 0) return b[i] + solve(i + 1, X, Y - 1, a, b, n);
 
  // When Y cannot take more orders
  if (Y <= 0) return a[i] + solve(i + 1, X - 1, Y, a, b, n);
  // When both can take order
  // calculate maximum out of two
  else
    return Math.max(
      a[i] + solve(i + 1, X - 1, Y, a, b, n),
      b[i] + solve(i + 1, X, Y - 1, a, b, n)
    );
}
 
// Driver code
 
let a = [1, 2, 3, 4, 5];
let b = [5, 4, 3, 2, 1];
n = a.length;
let x = 3,
  y = 3;
 
document.write(solve(0, x, y, a, b, n));
 
</script>


Output

21

Time Complexity: O(2n)

DP-based approach: The optimal substructure of the previous approach contains repetitions which could be avoided by storing previously calculated tips in the array. This would reduce the time complexity to O(n).

Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
// Global Variables
int N, X, Y;
 
vector<int> A_right_sum, B_right_sum;
vector<unordered_map<int,
                     unordered_map<int, int> > >
    mem;
vector<unordered_map<int,
                     unordered_map<int, bool> > >
    vis;
 
// Function to check if visited before
bool get_vis_val(int i, int x, int y)
{
    if (i == N)
        return true;
    return vis[i][x][y];
}
 
// Function to return the tip value
int get_mem_val(int i, int x, int y)
{
    if (i == N)
        return 0;
    return mem[i][x][y];
}
 
// Function to calculate the maximum tip possible
void find_ans(int i, int x, int y,
              vector<int> A, vector<int> B)
{
 
    // If already visited
    if (get_vis_val(i, x, y))
        return;
 
    vis[i][x][y] = true;
 
    // If X cannot take more orders
    if (x == 0) {
        mem[i][x][y] = B_right_sum[i];
    }
 
    // If Y cannot take more orders
    else if (y == 0) {
        mem[i][x][y] = A_right_sum[i];
    }
 
    // If both can take orders then
    // calculate the maximum of two
    else {
        find_ans(i + 1, x - 1, y, A, B);
        find_ans(i + 1, x, y - 1, A, B);
        mem[i][x][y]
            = max(get_mem_val(i + 1, x - 1, y)
                      + A[i],
                  get_mem_val(i + 1, x, y - 1)
                      + B[i]);
    }
}
 
// Driver code
int main()
{
 
    int a[] = { 1, 2, 3, 4, 5 };
    int b[] = { 5, 4, 3, 2, 1 };
    N = sizeof(a) / sizeof(a[0]);
    X = 3;
    Y = 3;
 
    // Vector containing the tips of waiter X
    vector<int> A(a, a + N);
 
    // Vector containing the tips of waiter Y
    vector<int> B(b, b + N);
 
    // Memory allocation and clearing
    // of previous caches
    mem.clear();
    mem.resize(N + 1);
    vis.clear();
    vis.resize(N + 1);
 
    A_right_sum.resize(N);
    B_right_sum.resize(N);
 
    A_right_sum[N - 1] = A[N - 1];
    B_right_sum[N - 1] = B[N - 1];
 
    // Precalculation of sums
    // of tip at each ith order
    for (int i = N - 2; i >= 0; i--) {
        A_right_sum[i]
            = A_right_sum[i + 1] + A[i];
        B_right_sum[i]
            = B_right_sum[i + 1] + B[i];
    }
 
    // Bottom up dp based solution
    find_ans(0, X, Y, A, B);
 
    // Final ans stored in mem[0][X][Y]
    cout << get_mem_val(0, X, Y) << endl;
 
    return 0;
}


Java




// Java program for the above approach
 
import java.util.*;
 
public class Main {
 
  static int N, X, Y;
  static List<Map<Integer, Map<Integer, Integer>>> mem = new ArrayList<>();
  static List<Map<Integer, Map<Integer, Boolean>>> vis = new ArrayList<>();
  static List<Integer> A_right_sum = new ArrayList<>();
  static List<Integer> B_right_sum = new ArrayList<>();
 
  // Function to check if visited before
  public static boolean get_vis_val(int i, int x, int y) {
    if (i == N)
      return true;
    return vis.get(i).get(x).get(y);
  }
 
 
  // Function to return the tip value
  public static int get_mem_val(int i, int x, int y) {
    if (i == N)
      return 0;
    return mem.get(i).get(x).get(y);
  }
 
 
  // Function to calculate the maximum tip possible
  public static void find_ans(int i, int x, int y, List<Integer> A, List<Integer> B) {
 
    // If already visited
    if (get_vis_val(i, x, y))
      return;
    vis.get(i).get(x).put(y, true);
 
    // If X cannot take more orders
    if (x == 0) {
      mem.get(i).get(x).put(y, B_right_sum.get(i));
    }
 
    // If Y cannot take more orders
    else if (y == 0) {
      mem.get(i).get(x).put(y, A_right_sum.get(i));
    }
    // If both can take orders then
    // calculate the maximum of two
    else {
      find_ans(i + 1, x - 1, y, A, B);
      find_ans(i + 1, x, y - 1, A, B);
      mem.get(i).get(x).put(y,
                            Math.max(get_mem_val(i + 1, x - 1, y) + A.get(i),
                                     get_mem_val(i + 1, x, y - 1) + B.get(i)));
    }
  }
 
  // Driver Code
  public static void main(String[] args) {
    int[] a = {1, 2, 3, 4, 5};
    int[] b = {5, 4, 3, 2, 1};
    N = a.length;
    X = 3;
    Y = 3;
 
    // Vector containing the tips of waiter X
    List<Integer> A = new ArrayList<>();
 
 
    // Vector containing the tips of waiter Y
    List<Integer> B = new ArrayList<>();
    for (int i = 0; i < N; i++) {
      A.add(a[i]);
      B.add(b[i]);
    }
    for (int i = 0; i <= N; i++) {
      mem.add(new HashMap<>());
      vis.add(new HashMap<>());
      for (int j = 0; j <= X; j++) {
        mem.get(i).put(j, new HashMap<>());
        vis.get(i).put(j, new HashMap<>());
        for (int k = 0; k <= Y; k++) {
          mem.get(i).get(j).put(k, 0);
          vis.get(i).get(j).put(k, false);
        }
      }
    }
    A_right_sum.add(A.get(N - 1));
    B_right_sum.add(B.get(N - 1));
 
    // Precalculation of sums
    // of tip at each ith order
    for (int i = N - 2; i >= 0; i--) {
      A_right_sum.add(0, A_right_sum.get(0) + A.get(i));
      B_right_sum.add(0, B_right_sum.get(0) + B.get(i));
    }
 
    // Bottom up dp based solution
    find_ans(0, X, Y, A, B);
 
    // Final ans stored in mem[0][X][Y]
    System.out.println(get_mem_val(0, X, Y));
  }
}
 
// This code is contributed by princekumaras


Python3




# Python program for the above approach:
 
## Global Variables
N = 0
X = 0
Y = 0
 
A_right_sum = []
B_right_sum = []
# vector<unordered_map<int, unordered_map<int, int> > > mem;
# vector<unordered_map<int, unordered_map<int, bool> > > vis;
mem = []
vis = []
 
## Function to check if visited before
def get_vis_val(i, x, y):
    if (i == N):
        return True
    if(x not in vis[i]):
        return False
    if(y not in vis[i][x]):
        return False
    return vis[i][x][y]
 
## Function to return the tip value
def get_mem_val(i, x, y):
    if (i == N):
        return 0
    if(x not in mem[i]):
        return 0
    if(y not in mem[i][x]):
        return 0
    return mem[i][x][y]
 
## Function to calculate the maximum tip possible
def find_ans(i, x, y, A, B):
 
    ## If already visited
    if (get_vis_val(i, x, y)):
        return;
 
    if(x not in vis[i]):
        vis[i][x] = {}
    vis[i][x][y] = True
 
    ## If X cannot take more orders
    if (x == 0):
        if(x not in mem[i]):
            mem[i][x] = {}
        mem[i][x][y] = B_right_sum[i]
 
    ## If Y cannot take more orders
    elif (y == 0):
        if(x not in mem[i]):
            mem[i][x] = {}
        mem[i][x][y] = A_right_sum[i]
 
    ## If both can take orders then
    ## calculate the maximum of two
    else:
        find_ans(i + 1, x - 1, y, A, B)
        find_ans(i + 1, x, y - 1, A, B)
        if(x not in mem[i]):
            mem[i][x] = {}
        mem[i][x][y] = max(get_mem_val(i + 1, x - 1, y) + A[i], get_mem_val(i + 1, x, y - 1) + B[i])
 
## Driver code
if __name__=='__main__':
 
    a = [ 1, 2, 3, 4, 5 ]
    b = [ 5, 4, 3, 2, 1 ]
    N = len(a)
    X = 3
    Y = 3
 
    ## Vector containing the tips of waiter X
    A = []
    for i in range(0, N):
        A.append(a[i])
 
    ## Vector containing the tips of waiter Y
    B = []
    for i in range(0, N):
        B.append(b[i])
 
    ## Memory allocation and clearing
    ## of previous caches
    mem.clear();
    for i in range(0, N+1):
        mem.append({})
 
    vis.clear();
    for i in range(0, N+1):
        vis.append({})
 
    for i in range(0, N):
        A_right_sum.append(0);
        B_right_sum.append(0);
 
    A_right_sum[N - 1] = A[N - 1];
    B_right_sum[N - 1] = B[N - 1];
 
    ## Precalculation of sums
    ## of tip at each ith order
    for i in range(N-2, -1, -1):
        A_right_sum[i] = A_right_sum[i + 1] + A[i]
        B_right_sum[i] = B_right_sum[i + 1] + B[i]
 
    ## Bottom up dp based solution
    find_ans(0, X, Y, A, B);
 
    ## Final ans stored in mem[0][X][Y]
    print(get_mem_val(0, X, Y))
 
    # This code is contributed by subhamgoyal2014.


C#




using System;
using System.Collections.Generic;
 
class Program
{
    static int N, X, Y;
    static List<Dictionary<int, Dictionary<int, int>>> mem = new List<Dictionary<int, Dictionary<int, int>>>();
    static List<Dictionary<int, Dictionary<int, bool>>> vis = new List<Dictionary<int, Dictionary<int, bool>>>();
    static List<int> A_right_sum = new List<int>();
    static List<int> B_right_sum = new List<int>();
 
    // Function to check if visited before
    public static bool GetVisValue(int i, int x, int y)
    {
        if (i == N)
            return true;
        return vis[i][x][y];
    }
 
    // Function to return the tip value
    public static int GetMemValue(int i, int x, int y)
    {
        if (i == N)
            return 0;
        return mem[i][x][y];
    }
 
    // Function to calculate the maximum tip possible
    public static void FindAns(int i, int x, int y, List<int> A, List<int> B)
    {
        // If already visited
        if (GetVisValue(i, x, y))
            return;
        vis[i][x][y] = true;
 
        // If X cannot take more orders
        if (x == 0)
        {
            mem[i][x][y] = B_right_sum[i];
        }
        // If Y cannot take more orders
        else if (y == 0)
        {
            mem[i][x][y] = A_right_sum[i];
        }
        // If both can take orders then
        // calculate the maximum of two
        else
        {
            FindAns(i + 1, x - 1, y, A, B);
            FindAns(i + 1, x, y - 1, A, B);
            mem[i][x][y] = Math.Max(GetMemValue(i + 1, x - 1, y) + A[i],
                                    GetMemValue(i + 1, x, y - 1) + B[i]);
        }
    }
 
    // Driver Code
    public static void Main()
    {
        int[] a = { 1, 2, 3, 4, 5 };
        int[] b = { 5, 4, 3, 2, 1 };
        N = a.Length;
        X = 3;
        Y = 3;
 
        // Vector containing the tips of waiter X
        List<int> A = new List<int>(a);
 
        // Vector containing the tips of waiter Y
        List<int> B = new List<int>(b);
 
        for (int i = 0; i <= N; i++)
        {
            mem.Add(new Dictionary<int, Dictionary<int, int>>());
            vis.Add(new Dictionary<int, Dictionary<int, bool>>());
            for (int j = 0; j <= X; j++)
            {
                mem[i].Add(j, new Dictionary<int, int>());
                vis[i].Add(j, new Dictionary<int, bool>());
                for (int k = 0; k <= Y; k++)
                {
                    mem[i][j].Add(k, 0);
                    vis[i][j].Add(k, false);
                }
            }
        }
 
        A_right_sum.Insert(0, A[N - 1]);
        B_right_sum.Insert(0, B[N - 1]);
 
        // Precalculation of sums
        // of tip at each ith order
        for (int i = N - 2; i >= 0; i--)
        {
            A_right_sum.Insert(0, A_right_sum[0] + A[i]);
            B_right_sum.Insert(0, B_right_sum[0] + B[i]);
        }
 
        // Bottom up dp based solution
        FindAns(0, X, Y, A, B);
 
        // Final ans stored in mem[0][X][Y]
        Console.WriteLine(GetMemValue(0, X, Y));
    }
}


Javascript




// JavaScript implementation of the approach
 
// Global Variables
let N, X, Y;
 
let A_right_sum, B_right_sum;
let mem, vis;
 
// Function to check if visited before
function getVisVal(i, x, y) {
    if (i === N) {
        return true;
    }
    return vis[i][x][y];
}
 
// Function to return the tip value
function getMemVal(i, x, y) {
    if (i === N) {
        return 0;
    }
    return mem[i][x][y];
}
 
// Function to calculate the maximum tip possible
function findAns(i, x, y, A, B) {
    // If already visited
    if (getVisVal(i, x, y)) {
        return;
    }
 
    vis[i][x][y] = true;
 
    // If X cannot take more orders
    if (x === 0) {
        mem[i][x][y] = B_right_sum[i];
    }
    // If Y cannot take more orders
    else if (y === 0) {
        mem[i][x][y] = A_right_sum[i];
    }
    // If both can take orders then calculate the maximum of two
    else {
        findAns(i + 1, x - 1, y, A, B);
        findAns(i + 1, x, y - 1, A, B);
        mem[i][x][y] = Math.max(
            getMemVal(i + 1, x - 1, y) + A[i],
            getMemVal(i + 1, x, y - 1) + B[i]
        );
    }
}
 
// Driver code
function main() {
    const a = [1, 2, 3, 4, 5];
    const b = [5, 4, 3, 2, 1];
    N = a.length;
    X = 3;
    Y = 3;
 
    // Vector containing the tips of waiter X
    const A = [...a];
 
    // Vector containing the tips of waiter Y
    const B = [...b];
 
    // Memory allocation and clearing of previous caches
    mem = new Array(N + 1).fill().map(() => new Array(X + 1).fill().map(() => new Array(Y + 1).fill(0)));
    vis = new Array(N + 1).fill().map(() => new Array(X + 1).fill().map(() => new Array(Y + 1).fill(false)));
 
    A_right_sum = new Array(N);
    B_right_sum = new Array(N);
 
    A_right_sum[N - 1] = A[N - 1];
    B_right_sum[N - 1] = B[N - 1];
 
    // Precalculation of sums of tip at each ith order
    for (let i = N - 2; i >= 0; i--) {
        A_right_sum[i] = A_right_sum[i + 1] + A[i];
        B_right_sum[i] = B_right_sum[i + 1] + B[i];
    }
 
    // Bottom up dp based solution
    findAns(0, X, Y, A, B);
 
    // Final ans stored in mem[0][X][Y]
    console.log(getMemVal(0, X, Y));
}
 
// Execute the main function
main();


Output

21

Time Complexity: O(N) 
Space Complexity: O(N2)
 



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