Given an M × N matrix where each cell can have a value of 1, 0, or -1, where -1 denotes an unsafe cell, collect the maximum number of ones starting from the first cell and by visiting only safe cells (i.e., 0 or 1). We can only go left or down if the row is odd; otherwise, we can only go right or down from the current cell.

For example, consider the following matrix shown on the left. The maximum value collected is 9 as marked.

 
Matrix Traversal Input                                    Matrix Traversal
 

Practice this problem

 
The idea is to use recursion. The problem has optimal substructure. That means the problem can be broken down into smaller, simple “subproblems”, which can further be divided into yet simpler, smaller subproblems until the solution becomes trivial. For matrix M, we can recursively define the problem as:

  if (M[i][j] != -1)
      path(i, j) = M[i][j] + | max(path(i, j – 1), path(i + 1, j))    (if i is odd)
                             | max(path(i, j + 1), path(i + 1, j))    (if i is even)
  else
      path(i, j) = 0

Here, path(i, j) calculates the maximum value that can be collected starting from cell (i, j). Following is the C++, Java, and Python implementation of the idea:

C++


Download  Run Code

Output:

The maximum value collected is 9

Java


Download  Run Code

Output:

The maximum value collected is 9

Python


Download  Run Code

Output:

The maximum value collected is 9

The time complexity of the proposed solution is exponential and occupies space in the call stack.
 

 
The problem clearly exhibits overlapping subproblems, so we will end up solving the same subproblem over and over again. The repeated subproblems can be seen by drawing a recursion tree for any M × N matrix. We know that problems having optimal substructure and overlapping subproblems can be solved by dynamic programming, in which subproblem solutions are saved rather than computed repeatedly.

In the following implementation in C++, Java, and Python, we use a bottom-up approach, i.e., we solve smaller subproblems first, then solve larger subproblems from them. It computes T[i][j], for each 1 <= i <= M and 1 <= j <= N, which stores the maximum value that can be collected till cell ending (i-1, j-1). It makes use of smaller values of i and j already computed and has the same asymptotic runtime as Memoization, but no recursion overhead.

C++


Download  Run Code

Output:

The maximum value collected is 9

Java


Download  Run Code

Output:

The maximum value collected is 9

Python


Download  Run Code

Output:

The maximum value collected is 9

The time complexity of the proposed solution is O(M × N) for an M × N matrix. The auxiliary space required by the program is O(M × N).