Treasure and Cities

• Difficulty Level : Hard
• Last Updated : 23 Jul, 2021

Given n cities: x1, x2, …… xn: each associated with T[i] (treasure) and C[i] (color). You can choose to visit a city or skip it. Only moving in the forward direction is allowed.When you visit a city you receive the following amount:

1. A*T[i] if the color of visited city is the same as color of previously visited city
2. B*T[i] if this is the first city visited or if the color of the visited city is different from the color of the previously visited city.The values of T[i], A and B can be negative while C[i] ranges from 1 to n.

We have to compute the maximum profit possible.

Examples:

Input :  A = -5, B = 7
Treasure = {4, 8, 2, 9}
color = {2, 2, 3, 2}
Output : 133
Visit city 2, 3 and 4. Profit = 8*7+2*7+9*7 = 133

Input : A = 5, B = -7
Treasure = {4, 8, 2, 9}
color = {2, 2, 3, 2}
Output: 57
Visit city 1, 2, 4. Profit = (-7)*4+8*5+9*5 = 57

Source : Oracle Interview Experience Set 61.

This is a variation of standard 0/1 Knapsack problem. The idea is to either visit a city or skip it and return the maximum of both the cases.

Below is the solution of above problem.

C++

 #include using namespace std; // k is current index and col is previous color.int MaxProfit(int treasure[], int color[], int n,              int k, int col, int A, int B){    int sum = 0;     if (k == n) // base case        return 0;     // we have two options    // either visit current city or skip that     // check if color of this city is equal    // to prev visited city    if (col == color[k])        sum += max(A * treasure[k] +                MaxProfit(treasure, color, n,                       k + 1, color[k], A, B),                MaxProfit(treasure, color, n,                          k + 1, col, A, B));    else        sum += max(B * treasure[k] +                                                         MaxProfit(treasure, color, n,                       k + 1, color[k], A, B),               MaxProfit(treasure, color, n,                          k + 1, col, A, B));     // return max of both options    return sum;} int main(){     int A = -5, B = 7;    int treasure[] = { 4, 8, 2, 9 };    int color[] = { 2, 2, 6, 2 };    int n = sizeof(color) / sizeof(color);     // Initially begin with color 0    cout << MaxProfit(treasure, color, n, 0, 0, A, B);    return 0;}

Java

 class GFG{ // k is current index and col is previous color.static int MaxProfit(int treasure[], int color[], int n,            int k, int col, int A, int B){    int sum = 0;     if (k == n) // base case        return 0;     // we have two options    // either visit current city or skip that     // check if color of this city is equal    // to prev visited city    if (col == color[k])        sum += Math.max(A * treasure[k] +                MaxProfit(treasure, color, n,                    k + 1, color[k], A, B),                MaxProfit(treasure, color, n,                        k + 1, col, A, B));    else        sum += Math.max(B * treasure[k] +                                                        MaxProfit(treasure, color, n,                    k + 1, color[k], A, B),            MaxProfit(treasure, color, n,                        k + 1, col, A, B));     // return max of both options    return sum;} public static void main(String[] args){     int A = -5, B = 7;    int treasure[] = { 4, 8, 2, 9 };    int color[] = { 2, 2, 6, 2 };    int n = color.length;     // Initially begin with color 0    System.out.print(MaxProfit(treasure, color, n, 0, 0, A, B));}} // This code is contributed by PrinciRaj1992

Python3

 # k is current index and col# is previous color.def MaxProfit(treasure, color, n,                    k, col, A, B):    sum = 0    if k == n:        return 0     # we have two options either    # visit current city or skip that     # check if color of this city    # is equal to prev visited city    if col== color[k]:        sum += max(A * treasure[k] +                MaxProfit(treasure, color, n,                       k + 1, color[k], A, B),                MaxProfit(treasure, color, n,                            k + 1, col, A, B))    else:        sum += max(B * treasure[k] +                                                      MaxProfit(treasure, color, n,                        k + 1, color[k], A, B),               MaxProfit(treasure, color, n,                           k + 1, col, A, B))     # return max of both options    return sum # Driver CodeA = -5B= 7treasure = [4, 8, 2, 9]color = [2, 2, 6, 2]n = len(color) # Initially begin with color 0print( MaxProfit(treasure, color,                 n, 0, 0, A, B)) # This code is contributed# by Shrikant13

C#

 using System; class GFG{ // k is current index and col is previous color.static int MaxProfit(int []treasure, int []color, int n,            int k, int col, int A, int B){    int sum = 0;     if (k == n) // base case        return 0;     // we have two options    // either visit current city or skip that     // check if color of this city is equal    // to prev visited city    if (col == color[k])        sum += Math.Max(A * treasure[k] +                MaxProfit(treasure, color, n,                    k + 1, color[k], A, B),                MaxProfit(treasure, color, n,                        k + 1, col, A, B));    else        sum += Math.Max(B * treasure[k] +                                                        MaxProfit(treasure, color, n,                    k + 1, color[k], A, B),            MaxProfit(treasure, color, n,                        k + 1, col, A, B));     // return max of both options    return sum;} // Driver codepublic static void Main(String[] args){     int A = -5, B = 7;    int []treasure = { 4, 8, 2, 9 };    int []color = { 2, 2, 6, 2 };    int n = color.Length;     // Initially begin with color 0    Console.Write(MaxProfit(treasure, color, n, 0, 0, A, B));}} // This code is contributed by PrinciRaj1992

Javascript


Output:
133

Since subproblems are evaluated again, this problem has Overlapping Subproblems property.

Following is Dynamic Programming based implementation.

C++

 // A memoization based program to find maximum// treasure that can be collected.#include using namespace std; const int MAX = 1001; int dp[MAX][MAX]; // k is current index and col is previous color.int MaxProfit(int treasure[], int color[], int n,              int k, int col, int A, int B){    if (k == n) // base case        return dp[k][col] = 0;     if (dp[k][col] != -1)        return dp[k][col];     int sum = 0;     // we have two options    // either visit current city or skip that     if (col == color[k]) // check if color of this city is equal to prev visited city        sum += max(A * treasure[k] +               MaxProfit(treasure, color, n, k + 1,                                     color[k], A, B),                MaxProfit(treasure, color, n, k + 1,                                        col, A, B));    else        sum += max(B * treasure[k] +                MaxProfit(treasure, color, n, k + 1,                                   color[k], A, B),                MaxProfit(treasure, color, n, k + 1,                                        col, A, B));     // return max of both options    return dp[k][col] = sum;} int main(){    int A = -5, B = 7;    int treasure[] = { 4, 8, 2, 9 };    int color[] = { 2, 2, 6, 2 };    int n = sizeof(color) / sizeof(color);    memset(dp, -1, sizeof(dp));    cout << MaxProfit(treasure, color, n, 0, 0, A, B);    return 0;}

Java

 // A memoization based program to find maximum// treasure that can be collected.import java.util.*; class GFG{ static int MAX = 1001; static int [][]dp = new int[MAX][MAX]; // k is current index and col is previous color.static int MaxProfit(int treasure[], int color[], int n,            int k, int col, int A, int B){    if (k == n) // base case        return dp[k][col] = 0;     if (dp[k][col] != -1)        return dp[k][col];     int sum = 0;     // we have two options    // either visit current city or skip that         // check if color of this city    // is equal to prev visited city    if (col == color[k])        sum += Math.max(A * treasure[k] +            MaxProfit(treasure, color, n, k + 1,                                    color[k], A, B),            MaxProfit(treasure, color, n, k + 1,                                        col, A, B));    else        sum += Math.max(B * treasure[k] +                MaxProfit(treasure, color, n, k + 1,                                color[k], A, B),                MaxProfit(treasure, color, n, k + 1,                                        col, A, B));     // return max of both options    return dp[k][col] = sum;} // Driver codepublic static void main(String[] args){    int A = -5, B = 7;    int treasure[] = { 4, 8, 2, 9 };    int color[] = { 2, 2, 6, 2 };    int n = color.length;    for (int i = 0; i < n; i++)        for (int j = 0; j < MAX; j++)            dp[i][j] = -1;    System.out.print(MaxProfit(treasure, color, n, 0, 0, A, B));}} // This code is contributed by 29AjayKumar

Python3

 # A memoization based program to find maximum# treasure that can be collected.MAX = 1001 dp = [[-1 for i in range(MAX)] for i in range(MAX)] # k is current index and col is previous color.def MaxProfit(treasure, color, n,k, col, A, B):    if (k == n):                 # base case        dp[k][col] = 0        return dp[k][col]    if (dp[k][col] != -1):        return dp[k][col]         summ = 0         # we have two options    # either visit current city or skip that    if (col == color[k]):                 # check if color of this city is equal to prev visited city        summ += max(A * treasure[k] + MaxProfit(treasure,                color, n, k + 1,color[k], A, B),                MaxProfit(treasure, color, n, k + 1, col, A, B))    else:        summ += max(B * treasure[k] + MaxProfit(treasure,                color, n, k + 1,color[k], A, B),                MaxProfit(treasure, color, n, k + 1, col, A, B))    dp[k][col] = summ         # return max of both options    return dp[k][col] # Driver codeA = -5B = 7treasure = [ 4, 8, 2, 9 ]color = [ 2, 2, 6, 2 ]n = len(color)print(MaxProfit(treasure, color, n, 0, 0, A, B)) # This code is contributed by shubhamsingh10

C#

 // A memoization based program to find maximum// treasure that can be collected.using System; class GFG{  static int MAX = 1001;  static int [,]dp = new int[MAX, MAX];  // k is current index and col is previous color.static int MaxProfit(int []treasure, int []color, int n,            int k, int col, int A, int B){    if (k == n) // base case        return dp[k, col] = 0;      if (dp[k, col] != -1)        return dp[k, col];      int sum = 0;      // we have two options    // either visit current city or skip that          // check if color of this city    // is equal to prev visited city    if (col == color[k])        sum += Math.Max(A * treasure[k] +            MaxProfit(treasure, color, n, k + 1,                                    color[k], A, B),            MaxProfit(treasure, color, n, k + 1,                                        col, A, B));    else        sum += Math.Max(B * treasure[k] +                MaxProfit(treasure, color, n, k + 1,                                color[k], A, B),                MaxProfit(treasure, color, n, k + 1,                                        col, A, B));      // return max of both options    return dp[k, col] = sum;}  // Driver codepublic static void Main(String[] args){    int A = -5, B = 7;    int []treasure = { 4, 8, 2, 9 };    int []color = { 2, 2, 6, 2 };    int n = color.Length;    for (int i = 0; i < n; i++)        for (int j = 0; j < MAX; j++)            dp[i, j] = -1;    Console.Write(MaxProfit(treasure, color, n, 0, 0, A, B));}} // This code is contributed by PrinciRaj1992

Javascript


Output:
133

My Personal Notes arrow_drop_up