Last Updated: 24 Apr, 2021

Minimum HP

Hard
Asked in companies
AmazonUberOptum

Problem statement

You are playing a board game where you die when your hp (health points) becomes 0 or negative. Now you start with some initial hp, and start moving in the board starting from the top-left corner. You have to reach the bottom right corner of the board by only moving right and down. Whenever you arrive on a cell in the board your hp may increase or decrease by the amount written on the cell. If the cell has a positive value it means your hp increases, if it has a negative value it means your hp decreases. You need to return the minimum initial health required so that you can reach the rightmost corner.

For Example:
In the example below, if we follow the path shown in the figure, then the minimum initial hp required will be 3.

board

Input Format :
The first line of the input contains ‘T,’ denoting the number of test cases. The 'T' test cases follow.

The first line of each test case contains two integers, ‘N’ and ‘M’, denoting the number of rows and columns of the board.

Next ‘N’ lines contain 'M' space-separated integers denoting the elements of the array 'board'.
Output Format :
For each test case, print an integer denoting the minimum initial hp required to reach the bottom-right corner of the board.

The output of each test case is printed in a separate line.
Note:
You do not need to print anything. It has already been taken care of. Just implement the given function.
Constraints :
1 <= T <= 5
1 <= N, M <= 1000
-3000 <= board[i][j] <= 3000

Where 'board[i][j]' represent the value of board at 'jth' column of 'ith' row.

Time Limit: 1 second

Approaches

01 Approach

The main idea is to use recursion to reduce the big problem into several smaller subproblems.

 

Algorithm :

 

  1. We will call a minimumHealth function that returns us the minimum health required from the current point to destination ('N' - 1, ‘M’ - 1).
  2. From each point ('i', ‘j’), we have 2 choices:
    • We can move right to ('i' , ‘j’ + 1). Then we will do a recursive call with ('i', ‘j’ + 1) as our starting point, say the minimum health required from this call comes out to be ‘op1’.
    • Or we can move down to ('i' + 1, ‘j’). Then we will do a recursive call with ('i' + 1, ‘j’) as our starting point, say the minimum health required from this call comes out to be ‘op2’.
    • our minimum health required from ('i' , ‘j’) to ('N' - 1, 'M' - 1) will be ‘board[i][j]' + min('op1', 'op2').
  3. The algorithm for minimumHealth will be as follows:
    • Int minimumHealth(‘board’, ‘i’, ‘j’, ‘N’, 'M)
      • If ‘i’ >= ‘N’ or ‘j’ >= ‘M’ :  if the point is out of grid.
        • return large integer value
      • If  ‘i’ == ‘N’ - 1 and j == ‘M’ - 1:
        • if board[i][j]' ≤ 0:
          1. return abs(board[i][j])+ 1
        • else:
          1. return 1
      • int ‘op1’ = minimumHealth (board, 'i', 'j' + 1, ‘N’, ‘M’)
      • int 'op2' = minimumHealth (‘board, ‘i’ + 1, ‘j’, ‘N’, ‘M’)
      • int minHealthRequired = min(op1, op2) - board[i][j];
        • if minHealthRequired ≤ 0:
          1. return 1
        • else
          1. return minHealthRequired.

02 Approach

We can see that we were solving the same subproblems multiple times. Thus, this problem was exhibiting overlapping subproblems. This means, in this approach, we need to eliminate the need to solve the same subproblems repeatedly. Thus, the idea is to use Memoization.

 

Algorithm :

 

The steps are as follows:

  1. Create a ‘dp’ table of size ‘N’ * ‘M’ to store the answers to the subproblems where ‘dp[i][j]’ denotes minimum health required from ('i', 'j') to ('N' - 1, 'M' - 1)
  2. Initialize the ‘dp’ array with -1 which denotes that it is not calculated yet.
  3. We will call a minimumHealth function that returns us the minimum path sum.
  4. The algorithm for minimumHealth will be as follows:
    • Int minimumHeath('board', ‘i’, ‘j’, ‘N', ‘M’)
      • If 'i' >= ‘N’ or ‘j’ >= 'M' : if the point is out of grid.
        • return a large integer value
      • If  ‘i’ == ‘N’ - 1 and ‘j’ == ‘M’ - 1:
        • if ‘board[i][j]' ≤ 0:
          1. return abs(board[i][j] + 1
        • else:
          1. return 1
      • If ‘dp[i][j]’ != -1: means we have already calculated the answer for this sub-problem,
        • return ‘dp[i][j]’.
      • Int ‘op1’ = minimumHealth(‘board’, ‘i’, ‘j’ + 1, ‘N’, 'M')
      • Int ‘op2’ = minimumHealth('board', 'i' + 1, 'j', ‘N’, ‘M’)
      • int minHealthRequired = min(op1, op2) - board[i][j];
      • if minHealthRequired ≤ 0:
        • dp[i][j] = 1
      • else
        • dp[i][j] = minHealthRequired
      • Return 'dp[i][j]'.

03 Approach

  • We will create a DP solution where dp[i][j] = minimum health needed from position (i, j) to reach position (n - 1, m - 1)
  • If we were to have only 1 value in the board ( i.e. N = 1, and M = 1) then the minimum initial hp required will have been = -board[0][0] +1. Therefore, dp[n - 1][m - 1] = 1- board[n - 1][m - 1]. Here 1 is added because we cannot have our hp reach 0.
  • From position (i, j) we can move to position (i + 1, j) and position (i, j+1). Thus we can find the value of dp[i][j] from dp[i + 1][j] and dp[i][j + 1].
  • After moving from (i, j) to (i + 1, j) we are gaining board[i + 1][j] hp. Conversely if we were to move from (i+1, j) to (i, j) we can look at it as losing board[i + 1][j] hp. Thus dp[i][j] may be dp[i + 1][j] - board[i][j].
  • Similarly dp[i][j] may be dp[i][j + 1] - board[i][j]. Or more specifically it will be the minimum of the two.
  • Do note if at any time our minimum initial hp becomes 0 or less, we set our minimum hp as 1 because initially we can’t have 0 hp.

 

Algorithm:

  • Create a ‘dp’ table of size N*M.
  • Set dp[n - 1][m - 1] =max(1,  1- board[n - 1][m - 1]).
  • Fill values in the last row in backward direction, for j={M-2,…, 0},
    • dp[n - 1][j] = max(1, dp[n - 1][j + 1] - board[n - 1][j] ).
  • Fill values in the last column in backward direction, for i={N - 2,…, 0},
    • dp[i][M - 1] = max(1, dp[i + 1][M - 1] - board[n - 1][j]) .
  • For i in {N - 2,…..,0}:
    • For j in {M - 2,....,0}:
      • dp[i][j]= min( max(1,dp[i + 1][j] - board[i][j] ), max(1,dp[i][j + 1]-board[i][j]))
  • Return dp[0][0]