📌  相关文章
📜  从矩阵左上角到右下角并返回的最大点

📅  最后修改于: 2021-05-04 08:11:35             🧑  作者: Mango

给定大小为NXM的矩阵,其中包括“#”,“。”和 ‘*’。 “#”表示路径受阻,“。”表示可步行的路径,“ *”表示必须收集的点。现在考虑您在矩阵的左上方。您必须到达矩阵的右下角,然后回到左上角。当您从左上方移动到右下方时,您可以向右或向下行走。而且,当您从右下到左上移动时,您可以向左或向上行走。任务是找到您在整个旅程中可以获得的最高积分。一旦获得积分,将转换为“。”。即步行路径。

例子:

Input : N = 3, M = 4
****
.##.
.##.
****
Output : 8

Input : N = 9, M = 7
*........
.....**#.
..**...#*
..####*#.
.*.#*.*#.
...#**...
*........
Output : 7

如果考虑两条路径-一个从(0,0)到(N – 1,M – 1),另一个从(N – 1,M – 1)到(0,0),并在每个路径中收集最大*。您可能会得到错误的答案。如果分别添加两条路径的答案,则在回溯时将再次计算相交点。本质上,以相同的路径结束。即使您保留一个访问数组,并在第一个路径上标记每个*,您仍然不会得到正确的答案。
考虑以下示例:

如果我们考虑作为两条独立的路径,那么

总共*收集的是7。
而遵循以下路径可以收集的最大点数是8。

每个路径上有4 *。因此,总数= 8。
因此,我们看到最优解不是两个路径的最优解之和。一个人的最佳答案不能确保最佳答案。

因此,我们将必须同时计算两条路径。之所以需要这样做,是因为路径2的答案取决于路径1选择的路径。可以通过考虑从(0,0)到(N-1,M-1)的两条路径并在每个位置做出四个决策来完成同时计算。 (每个两个)。
因此,我们将同时从(0,0)到(N-1,M-1)两条路径,而不是从左上角到右下角的两条路径,而从(0,0)到(N-1,M-1)两条路径,一步,我们对这两个路径都迈出了一步。因此,我们的状态将由(x1,y1,x2,y2)组成,其中(x1,y1)是第一条路径的位置,而(x2,y2)是第二条游客在网格中的位置。
注意事项:
1.在每一步中,任一步都可以向右或向下移动,因此我们有4个移动选择(每个路径2个选择)。
2.如果两个路径都在同一个像元上(x1 == x2和y1 == y2),则如果该像元具有*,则只能加1。
3.我们可以通过将状态维数从4减小到3来降低复杂度。如果我们知道第一条路径(x1,y1)的位置是第二条路径x2的x坐标,那么由于x1 + y1 = x2 + y2两条路径在相同的时间内覆盖相同的距离。因此y2 = x1 + y1 – x2,我们的状态仅取决于(x1,y1,x2)。

以下是此方法的实现:

C++
// 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 
#define MAX 5
#define N 5
#define M 5
#define inf 100000
using namespace std;
  
// Calculating the points at a (row1, col1) && 
// (row2, col2) from path1 && path2
int 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 (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 (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 (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 (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 Function
int 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 blcoked
    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 Program
int main()
{
    int n = 5, m = 5;
  
    char grid[N][M] = {
        { '.', '*', '.', '*', '.' },
        { '*', '#', '#', '#', '.' },
        { '*', '.', '*', '.', '*' },
        { '.', '#', '#', '#', '*' },
        { '.', '*', '.', '*', '.' }
    };
  
    cout << wrapper(n, m, grid) << endl;
    return 0;
}


Python3
# 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 = 5
N = 5
M = 5
inf = 100000
  
# Calculating the points at a (row1, col1) and 
# (row2, col2) from path1 and path2 
def 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 Function 
def 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 blcoked 
    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 Code
if __name__ == '__main__': 
    n = 5
    m = 5
  
    grid = [[ '.', '*', '.', '*', '.' ], 
            [ '*', '#', '#', '#', '.' ], 
            [ '*', '.', '*', '.', '*' ], 
            [ '.', '#', '#', '#', '*' ], 
            [ '.', '*', '.', '*', '.' ]] 
      
    print(wrapper(n, m, grid)) 
      
# This code is contributed by ashutosh450


输出:

8

时间复杂度: O(N ^ 3)