Samsung Semiconductor Institute of Research(SSIR Software) Intern/FTE | Set-2

There are N Balloons marked with value Bi (where B(i…N)).
User will be given Gun with N Bullets and user must shot N times.
When any balloon explodes then its adjacent balloons becomes next to each other.
User has to score highest points to get the prize and score starts at 0.
Below is the condition to calculate the score.
When Balloon Bi Explodes then score will be a product of Bi-1 & Bi+1 (score = Bi-1 * Bi+1).
When Balloon Bi Explodes and there is only left Balloon present then score will be Bi-1.
When Balloon Bi Explodes and there is only right Balloon present then score will be Bi+1.
When Balloon Bi explodes and there is no left and right Balloon present then score will be Bi.
Write a program to score maximum points.

Example: 
Input: B[] = {1, 2, 3, 4}
Output: 20
Explanation:
For max score:
3 explodes, score= 4*2=8 (product of adjacent balloons) 
2 explodes score= 4*1 + 8 = 12 (product of adjacent balloons) 
1 explodes score=  4 + 12= 16  (only 4 is left on the left side)
4 explodes score = 4 + 16 = 20 (no balloons left so add 4)
score =20
other combinations will result in lesser scores.

Analysis:
1) Aim is to find max score
2) Max score depends on points on neighbour, however there is no easy way to find which sequence which gives max score, so only way is to find the all possible sequence can get max out of it.
3) As order matters in sequence for input N we can have N! sequences, ie. nPn ways (1st balloon N ways, 2nd N-1 ways …last balloon 1 ways N*(N-1)(N-2)..2*1= N!

Complexity:
To generate the all sequence O(N!)
To Get the Score for 1 sequence, for each balloon in sequence we need to left and right neighbors worst case need complete traversal in array so complexity is O(N*N)
Total complexity is O(N!) * O(N*N) (note: computation has done at end of each sequence)
50 TC, N 50 * is O(N! * N*N) => 50 * 100 * 10! => 5000 * 3628800 => 1.5 * 10^10 this cannot be executed in given 3 sec ( 10^9 instruction per second).
So need to look for optimization

Pseudo code to generate all sequences:

INPUT[N]
CHOICE[N] <= -1 //initialize to -1
Permute(0)
Permute(Position)
{
   // stop condition
   If ( all balloon shot )
   {
     Compute the score for this sequence in CHOICE[]
     If score better than previous then store
   }
 
   For i:0~N-1
   {
     If (ith balloon not selected // CHOICE[i]==-1)
     {
        Select ith balloon  // CHOICE[Position]= i 
        Permute (Position+1)
        Unselect ith balloon// CHOICE[Position]= -1
     }
   }
}

Optimization:
We can see in above algorithm 2 major operation are carried out
(1) generate all sequence O(N!)
(2) computing score for each sequence O(N*N)
We cannot optimize the algorithm generate all sequences however we can reduce the computing part further.
Optimization computing part
If can optimize the finding the neighbor to O(1) we can reduce computation part to O(N) which leads our algo to execute in 1.5 * 10^9 which can be achieved in 3 sec.
Alternatively we can compute the score for each chosen balloon to shoot “on the go” here finding neighbor is extra when each time balloon is chosen which can be O(N) and also reduce 1.5 * 10^9



Algorithm to get neighbours:
Naïve method by O(N):
Neighbor(chosen)
For Left: chosen-1~0 if Left th balloon not chosen break;
For Right: chosen+1~N-1 if right th balloon not chosen break;
if(Right==N)
Right=-1;
Return   Left and right ;

Optimized way by O(1)
1.Keep 2 array left[] and right[] which contain neighbors of each balloon.
2.Initially neighbor are known, for ith balloon left is i-1 and right is i+1 except that 1st balloon will have no left and last have no right.
3.When balloon is chosen we can obtain its right and left by O(1)
4.When a balloon is shot update neighbor left[i+1]=left[i] right[i-1]=right[i]
Note:
Instead of calling the new function to get left and right calculating left and right inside the recursive faction will reduce many hidden instructions as to call new function compiler add many instruction which can be reduced

Alternative way:
Way to compute the score on the go
Pass current score variable to recursive function
When a balloon is chosen to shoot get the left and right neighbors
Compute the score gained by shooting chosen balloon
Add this to given score and pass to next level
Pseudo Code:
 

 
Permute(Position, score)
{
   // stop condition
   If( all balloon shot )
   {
     If score better than previous then store
   }
 
   For i:0~N-1
   {
      If (ith balloon not selected // CHOICE[i]==-1)
      {
         Select ith balloon  // CHOICE[Position]= i 
         Gain = Compute the gain by shooting ith balloon 
         Permute (Position+1, score+ Gain)
         Unselect ith balloon// CHOICE[Position]= -1
      }
   }
} 

Alternative optimized approach(Divide and Conquer) and Dynamic programming

The problem at first doesn’t seem like a divide and conquer problem.
Reason: If we select a balloon(for bursting) then our array would be divided into two sub arrays. But these two sub arrays won’t be independent sub problems.
Example
Consider 5 balloons B1, .., B5. Bursting B3 divides the array into two sub-array {B1, B2} and {B4, B5}. But these two sub array are not independent of each other ie. score for bursting B4 is dependent on bursting order of {B1, B2}.

Key Insight
1.To divide the problem into two halves we have to ensure that any action(bursting of balloon) in one half doesn’t affect score of the other half.
2.If we fix a balloon and ensure that we won’t burst it until we burst all the balloons to the left of it and all the balloon to the right of it then we can successfully divide the problem into two sub-problems.

Example
Consider the previous case of five balloons. Now instead of bursting B3 we fix that we will burst B3 after all the balloons this makes {B1, B2} and {B4, B5} independent of each other ie score for bursting B4 is now independent of {B1, B2}.
table

Another way to visualize the divide and conquer approach is that we think of the problem in reverse. The parallel problem would be given a set of n deflated balloons each with a score, choose the order in which you will inflate the balloon. The score for inflating the balloon is equal to product of score attached to the balloons located left and right to the mentioned balloon.

Below is the recursive solution:

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <iostream>
using namespace std;
  
// recursive function to generate scores
int getmaxscore(int arr[], int l, int r, int n)
{
    int mscore = 0;
    for (int i = l + 1; i < r; i++) {
  
        // to permute through all cases
        int cs = getmaxscore(arr, l, i, n) + getmaxscore(arr, i, r, n);
        if (l == 0 && r == n)
            cs = cs + arr[i];
        else
            cs = cs + (arr[l] * arr[r]);
  
        if (cs > mscore)
            mscore = cs;
    }
    return mscore;
}
  
int main() // driver function
{
    int n = 4; // no of balloons
  
    // assigning scores to each balloon 1-based indexing
    // arr[0]=1 because to calculate score when no 
    //             balloons are left after popping
    // arr[5]=1 because to calculate score when no
    //             balloons are left after popping
    // scores of balloons are assigned from 1 to 4 i.e 1 to n
    int arr[] = { 1, 1, 2, 3, 4, 1 }; 
  
    /* for input input arr[n+2], 
      arr[0]=1 && arr[n+1]=1
      cin>>n;
      for(int i=1;i<=n;i++)
         cin>>arr[i]; */
  
    cout << getmaxscore(arr, 0, n + 1, n + 1) << "\n";
  
    return 0;
}

chevron_right


Output:
20


Write your Interview Experience or mail it to contribute@geeksforgeeks.org



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.