Maximum points from top left of matrix to bottom right and return back

27 May, 2022
Given a matrix of size N X M consisting of ‘#’, ‘.’ and ‘*’. ‘#’ means blocked path, ‘.’ means walkable path and ‘*’ means points that you have to collect. Now consider you are at the top left of the matrix. You have to reach the bottom right of the matrix and come back to the top left. When you are moving top left to bottom right, you are allowed to walk right or down. And when you are moving the bottom right to top left, you are allowed to walk left or up. The task is to find the maximum points you can grab during your whole journey. Points once taken will be converted into ‘.’ i.e walkable path.Examples:  
Input : N = 3, M = 4
****
.##.
.##.
****
Output : 8

Input : N = 9, M = 7
*........
.....**#.
..**...#*
..####*#.
.*.#*.*#.
...#**...
*........
Output : 7
 
If you consider two paths – one from (0, 0) to (N – 1, M – 1) and another from (N – 1, M – 1) to (0, 0) and collect maximum * in each path. You might end up with wrong answer. If you add the answer of both the paths independently, you will be calculating the intersecting points once again while backtracking. Essentially, ending up with the same path. Even if you keep a visited array, marking every * on the first path, you will still not end up with the correct answer. Consider the following example:  
If we consider as two independent path, then  
total * collected is 7. Whereas the maximum points collected can be 8 by following paths.  
There are 4 * on each path. Hence, total = 8. Thus we see that the optimal solution is not the sum of optimal solutions of both the path independently. The optimal answer for one does not ensure an optimal answer.So, we will have to calculate both the paths simultaneously. This is needed because the answer for path 2 depends on the route chosen by path 1. Simultaneous calculations can be done by considering two paths from (0, 0) to (N-1, M-1) and making four decisions at each position (two for each). So instead of two traveling one path from top left to the bottom right and other from the bottom right to top left, we will travel two paths from (0, 0) to (N-1, M-1) simultaneously, so at each step, we take one step for both paths. So our state will consist of (x1, y1, x2, y2) where (x1, y1) is the position of the first path and (x2, y2) is the position of the second tourist in the grid. Points to notice: 1. At each step either step can move right or down, so we have 4 choices for movement(2 choices for each path). 2. If both paths are on the same cell (x1 == x2 and y1 == y2) then we can add only 1 to result if that cell has *. 3. We can reduce the complexity by reducing the state dimension from 4 to 3. If we know the position of first path (x1, y1) the x coordinate of second path x2, then we must have x1 + y1 = x2 + y2 since both path cover the same distance in the same amount of time. So y2 = x1 + y1 – x2 and our state depends only on (x1, y1, x2).Below is the implementation of this approach:  
C++
Java
Python3
Javascript
// CPP program to find maximum points that can// be collected in a journey from top to bottom// and then back from bottom to top,#include <bits/stdc++.h>#define MAX 5#define N 5#define M 5#define inf 100000using namespace std; // Calculating the points at a (row1, col1) &&// (row2, col2) from path1 && path2int cost(char grid[][M], int row1, int col1,                           int row2, int col2){    // If both path is at same cell    if (row1 == row2 && col1 == col2) {         // If the cell contain *, return 1        if (grid[row1][col1] == '*')            return 1;         // else return 0.        return 0;    }     int ans = 0;     // If path 1 contain *, add to answer.    if (grid[row1][col1] == '*')        ans++;     // If path  contain *, add to answer.    if (grid[row2][col2] == '*')        ans++;     return ans;} // Calculate the maximum points that can be// collected.int solve(int n, int m, char grid[][M],         int dp[MAX][MAX][MAX], int row1,                      int col1, int row2){    int col2 = (row1 + col1) - (row2);     // If both path reach the bottom right cell    if (row1 == n - 1 && col1 == m - 1 &&        row2 == n - 1 && col2 == m - 1)        return 0;     // If moving out of grid    if (row1 >= n || col1 >= m ||        row2 >= n || col2 >= m)        return -1 * inf;     // If already calculated, return the value    if (dp[row1][col1][row2] != -1)        return dp[row1][col1][row2];     // Variable for 4 options.    int ch1 = -1 * inf, ch2 = -1 * inf;    int ch3 = -1 * inf, ch4 = -1 * inf;     // If path 1 is moving right and path 2    // is moving down.    if (col1 + 1 < m && row2 + 1 < n && grid[row1][col1 + 1] != '#' &&        grid[row2 + 1][col2] != '#')      ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2) +        solve(n, m, grid, dp, row1, col1 + 1, row2 + 1);     // If path 1 is moving right and path 2 is moving    // right.    if (col2 + 1 < m && col1 + 1 < m && grid[row1][col1 + 1] != '#' &&        grid[row2][col2 + 1] != '#')      ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1) +            solve(n, m, grid, dp, row1, col1 + 1, row2);     // If path 1 is moving down and path 2 is moving right.    if (col2 + 1 < m && row1 + 1 < n && grid[row1 + 1][col1] != '#' &&        grid[row2][col2 + 1] != '#')     ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1) +           solve(n, m, grid, dp, row1 + 1, col1, row2);     // If path 1 is moving down and path 2 is moving down.    if (row1 + 1 < n && row2 + 1 < n && grid[row1 + 1][col1] != '#' &&        grid[row2 + 1][col2] != '#')      ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2) +         solve(n, m, grid, dp, row1 + 1, col1, row2 + 1);     // Returning the maximum of 4 options.    return dp[row1][col1][row2] = max({ch1, ch2, ch3, ch4});} // Wrapper Functionint wrapper(int n, int m, char grid[N][M]){    int ans = 0;    int dp[MAX][MAX][MAX];    memset(dp, -1, sizeof dp);     // If last bottom right cell is blocked    if (grid[n - 1][m - 1] == '#' || grid[0][0] == '#')        ans = -1 * inf;     // If top left cell contain *    if (grid[0][0] == '*')        ans++;    grid[0][0] = '.';     // If bottom right cell contain *    if (grid[n - 1][m - 1] == '*')        ans++;    grid[n - 1][m - 1] = '.';     ans += solve(n, m, grid, dp, 0, 0, 0);    return max(ans, 0);} // Driven Programint main(){    int n = 5, m = 5;     char grid[N][M] = {        { '.', '*', '.', '*', '.' },        { '*', '#', '#', '#', '.' },        { '*', '.', '*', '.', '*' },        { '.', '#', '#', '#', '*' },        { '.', '*', '.', '*', '.' }    };     cout << wrapper(n, m, grid) << endl;    return 0;}
// Java program to find maximum points that can// be collected in a journey from top to bottom// and then back from bottom to top,import java.io.*; class GFG {     static int MAX = 5;    static int N = 5;    static int M = 5;    static int inf = 100000;     // Calculating the points at a (row1, col1) &&    // (row2, col2) from path1 && path2    public static int cost(char grid[][], int row1,                           int col1, int row2, int col2)    {        // If both path is at same cell        if (row1 == row2 && col1 == col2) {             // If the cell contain *, return 1            if (grid[row1][col1] == '*')                return 1;             // else return 0.            return 0;        }         int ans = 0;         // If path 1 contain *, add to answer.        if (grid[row1][col1] == '*')            ans++;         // If path  contain *, add to answer.        if (grid[row2][col2] == '*')            ans++;         return ans;    }     // Calculate the maximum points that can be    // collected.    public static int solve(int n, int m, char grid[][],                            int dp[][][], int row1,                            int col1, int row2)    {        int col2 = (row1 + col1) - (row2);         // If both path reach the bottom right cell        if (row1 == n - 1 && col1 == m - 1 && row2 == n - 1            && col2 == m - 1)            return 0;         // If moving out of grid        if (row1 >= n || col1 >= m || row2 >= n            || col2 >= m)            return -1 * inf;         // If already calculated, return the value        if (dp[row1][col1][row2] != -1)            return dp[row1][col1][row2];         // Variable for 4 options.        int ch1 = -1 * inf, ch2 = -1 * inf;        int ch3 = -1 * inf, ch4 = -1 * inf;         // If path 1 is moving right and path 2        // is moving down.        if (col1 + 1 < m && row2 + 1 < n            && grid[row1][col1 + 1] != '#'            && grid[row2 + 1][col2] != '#')            ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2)                  + solve(n, m, grid, dp, row1, col1 + 1,                          row2 + 1);         // If path 1 is moving right and path 2 is moving        // right.        if (col2 + 1 < m && col1 + 1 < m            && grid[row1][col1 + 1] != '#'            && grid[row2][col2 + 1] != '#')            ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1)                  + solve(n, m, grid, dp, row1, col1 + 1,                          row2);         // If path 1 is moving down and path 2 is moving        // right.        if (col2 + 1 < m && row1 + 1 < n            && grid[row1 + 1][col1] != '#'            && grid[row2][col2 + 1] != '#')            ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1)                  + solve(n, m, grid, dp, row1 + 1, col1,                          row2);         // If path 1 is moving down and path 2 is moving        // down.        if (row1 + 1 < n && row2 + 1 < n            && grid[row1 + 1][col1] != '#'            && grid[row2 + 1][col2] != '#')            ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2)                  + solve(n, m, grid, dp, row1 + 1, col1,                          row2 + 1);         // Returning the maximum of 4 options.        return dp[row1][col1][row2] = Math.max(                   ch1, Math.max(ch2, Math.max(ch3, ch4)));    }     // Wrapper Function    public static int wrapper(int n, int m, char grid[][])    {        int ans = 0;        int dp[][][] = new int[MAX][MAX][MAX];        for (int i = 0; i < MAX; i++)            for (int j = 0; j < MAX; j++)                for (int k = 0; k < MAX; k++)                    dp[i][j][k] = -1;         // If last bottom right cell is blocked        if (grid[n - 1][m - 1] == '#' || grid[0][0] == '#')            ans = -1 * inf;         // If top left cell contain *        if (grid[0][0] == '*')            ans++;        grid[0][0] = '.';         // If bottom right cell contain *        if (grid[n - 1][m - 1] == '*')            ans++;        grid[n - 1][m - 1] = '.';         ans += solve(n, m, grid, dp, 0, 0, 0);        return Math.max(ans, 0);    }     // Driver Code    public static void main(String[] args)    {        int n = 5, m = 5;         char grid[][] = { { '.', '*', '.', '*', '.' },                          { '*', '#', '#', '#', '.' },                          { '*', '.', '*', '.', '*' },                          { '.', '#', '#', '#', '*' },                          { '.', '*', '.', '*', '.' } };         System.out.println(wrapper(n, m, grid));    }} // This code is contributed by Rohit Pradhan
# Python3 program to find maximum points# that can be collected in a journey from# top to bottom and then back from bottom to top,MAX = 5N = 5M = 5inf = 100000 # Calculating the points at a (row1, col1) and# (row2, col2) from path1 and path2def cost(grid, row1, col1, row2, col2):     # If both path is at same cell    if (row1 == row2 and col1 == col2):         # If the cell contain *, return 1        if (grid[row1][col1] == '*'):            return 1         # else return 0.        return 0     ans = 0     # If path 1 contain *, add to answer.    if (grid[row1][col1] == '*'):        ans += 1     # If path contain *, add to answer.    if (grid[row2][col2] == '*'):        ans += 1     return ans # Calculate the maximum points that can be# collected.def solve(n, m, grid, dp, row1, col1, row2):     col2 = (row1 + col1) - (row2)     # If both path reach the bottom right cell    if (row1 == n - 1 and col1 == m - 1 and        row2 == n - 1 and col2 == m - 1):        return 0     # If moving out of grid    if (row1 >= n or col1 >= m or        row2 >= n or col2 >= m):        return -1 * inf     # If already calculated, return the value    if (dp[row1][col1][row2] != -1):        return dp[row1][col1][row2]     # Variable for 4 options.    ch1 = -1 * inf    ch2 = -1 * inf    ch3 = -1 * inf    ch4 = -1 * inf     # If path 1 is moving right and path 2    # is moving down.    if (col1 + 1 < m and row2 + 1 < n and          grid[row1][col1 + 1] != '#' and          grid[row2 + 1][col2] != '#'):        ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2) + \             solve(n, m, grid, dp, row1, col1 + 1, row2 + 1)     # If path 1 is moving right and path 2    # is moving right.    if (col1 + 1 < m and col2 + 1 < m and          grid[row1][col1 + 1] != '#' and          grid[row2][col2 + 1] != '#'):        ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1) + \             solve(n, m, grid, dp, row1, col1 + 1, row2)     # If path 1 is moving down and path 2    # is moving right.    if (row1 + 1 < n and col2 + 1 < m and          grid[row1 + 1][col1] != '#' and          grid[row2][col2 + 1] != '#'):        ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1) + \             solve(n, m, grid, dp, row1 + 1, col1, row2)     # If path 1 is moving down and path 2 is moving down.    if (row1 + 1 < n and row2 + 1 < n and          grid[row1 + 1][col1] != '#' and          grid[row2 + 1][col2] != '#'):        ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2) + \             solve(n, m, grid, dp, row1 + 1, col1, row2 + 1)     # Returning the maximum of 4 options.    dp[row1][col1][row2] = max(ch1, ch2, ch3, ch4)    return dp[row1][col1][row2] # Wrapper Functiondef wrapper(n, m, grid):     ans = 0     dp = [[[-1] * MAX for i in range(MAX)]                      for j in range(MAX)]     # If last bottom right cell is blocked    if (grid[n - 1][m - 1] == '#' or        grid[0][0] == '#'):        ans = -1 * inf     # If top left cell contain *    if (grid[0][0] == '*'):        ans += 1    grid[0][0] = '.'     # If bottom right cell contain *    if (grid[n - 1][m - 1] == '*'):        ans += 1    grid[n - 1][m - 1] = '.'     ans += solve(n, m, grid, dp, 0, 0, 0)    return max(ans, 0) # Driver Codeif __name__ == '__main__':    n = 5    m = 5     grid = [[ '.', '*', '.', '*', '.' ],            [ '*', '#', '#', '#', '.' ],            [ '*', '.', '*', '.', '*' ],            [ '.', '#', '#', '#', '*' ],            [ '.', '*', '.', '*', '.' ]]         print(wrapper(n, m, grid))     # This code is contributed by ashutosh450
<script>// JavaScript program to find maximum points// that can be collected in a journey from// top to bottom && then back from bottom to top,const MAX = 5const N = 5const M = 5const inf = 100000 // Calculating the points at a (row1, col1) &&// (row2, col2) from path1 && path2function cost(grid, row1, col1, row2, col2){     // If both path is at same cell    if (row1 == row2 && col1 == col2){         // If the cell contain *, return 1        if (grid[row1][col1] == '*'){            return 1        }         // else return 0.        return 0    }     let ans = 0     // If path 1 contain *, add to answer.    if (grid[row1][col1] == '*')        ans += 1     // If path contain *, add to answer.    if (grid[row2][col2] == '*')        ans += 1     return ans} // Calculate the maximum points that can be// collected.function solve(n, m, grid, dp, row1, col1, row2){     let col2 = (row1 + col1) - (row2)     // If both path reach the bottom right cell    if (row1 == n - 1 && col1 == m - 1 &&        row2 == n - 1 && col2 == m - 1)        return 0     // If moving out of grid    if (row1 >= n || col1 >= m ||        row2 >= n || col2 >= m)        return -1 * inf     // If already calculated, return the value    if (dp[row1][col1][row2] != -1)        return dp[row1][col1][row2]     // Variable for 4 options.    let ch1 = -1 * inf    let ch2 = -1 * inf    let ch3 = -1 * inf    let ch4 = -1 * inf     // If path 1 is moving right && path 2    // is moving down.    if (col1 + 1 < m && row2 + 1 < n &&        grid[row1][col1 + 1] != '#' &&        grid[row2 + 1][col2] != '#'){        ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2) +        solve(n, m, grid, dp, row1, col1 + 1, row2 + 1)    }     // If path 1 is moving right && path 2    // is moving right.    if (col1 + 1 < m && col2 + 1 < m &&        grid[row1][col1 + 1] != '#' &&        grid[row2][col2 + 1] != '#')        ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1) +        solve(n, m, grid, dp, row1, col1 + 1, row2)     // If path 1 is moving down && path 2    // is moving right.    if (row1 + 1 < n && col2 + 1 < m &&        grid[row1 + 1][col1] != '#' &&        grid[row2][col2 + 1] != '#')        ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1) +        solve(n, m, grid, dp, row1 + 1, col1, row2)     // If path 1 is moving down && path 2 is moving down.    if (row1 + 1 < n && row2 + 1 < n &&        grid[row1 + 1][col1] != '#' &&        grid[row2 + 1][col2] != '#')        ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2) +        solve(n, m, grid, dp, row1 + 1, col1, row2 + 1)     // Returning the maximum of 4 options.    dp[row1][col1][row2] = Math.max(ch1, ch2, ch3, ch4)    return dp[row1][col1][row2]} // Wrapper Functionfunction wrapper(n, m, grid){     let ans = 0     let dp = new Array(MAX)    for(let i = 0; i < MAX; i++)    {        dp[i] = new Array(MAX);        for(let j = 0; j < MAX; j++)        {            dp[i][j] = new Array(MAX).fill(-1);        }    }     // If last bottom right cell is blocked    if (grid[n - 1][m - 1] == '#' ||        grid[0][0] == '#')        ans = -1 * inf     // If top left cell contain *    if (grid[0][0] == '*')        ans += 1    grid[0][0] = '.'     // If bottom right cell contain *    if (grid[n - 1][m - 1] == '*')        ans += 1    grid[n - 1][m - 1] = '.'     ans += solve(n, m, grid, dp, 0, 0, 0)    return Math.max(ans, 0)} // Driver Codelet n = 5let m = 5 let grid = [[ '.', '*', '.', '*', '.' ],            [ '*', '#', '#', '#', '.' ],            [ '*', '.', '*', '.', '*' ],            [ '.', '#', '#', '#', '*' ],            [ '.', '*', '.', '*', '.' ]]     document.write(wrapper(n, m, grid))     // This code is contributed by shinjanpatra </script>
8
Time Complexity: O(N^3)This article is contributed by Anuj Chauhan. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above. 
Akanksha_Rai
ashutosh450
rudradesai
shinjanpatra
simmytarika5
rohit768
Dynamic Programming
Matrix
Dynamic Programming
Matrix
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Floyd Warshall Algorithm | DP-16
Matrix Chain Multiplication | DP-8
Bellman–Ford Algorithm | DP-23
Minimum number of jumps to reach end
Travelling Salesman Problem | Set 1 (Naive and Dynamic Programming)
Matrix Chain Multiplication | DP-8
Print a given matrix in spiral form
Program to find largest element in an array
Sudoku | Backtracking-7
Find the number of islands | Set 1 (Using DFS)