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

📅  最后修改于: 2021-09-17 07:16:32             🧑  作者: 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) 行进两条路径,而不是两个从左上角到右下角以及从右下角到左上角的一条路径,因此在每个step,我们在两条路径上都迈出一步。所以我们的状态将由 (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)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。