📌  相关文章
📜  最大化从给定矩阵的左上角和右上角到达最底行的成本

📅  最后修改于: 2022-05-13 01:56:04.463000             🧑  作者: Mango

最大化从给定矩阵的左上角和右上角到达最底行的成本

给定一个大小为M * N的矩阵grid[][] ,其中矩阵的每个单元格表示该单元格上存在的成本。任务是最大化从矩阵的左上角和右上角移动到最底行的成本,其中每一步:

  • 从单元格(i, j)可以移动到(i+1, j-1)(i+1, j)(i+1, j+1)
  • 如果两个点同时在同一个单元格中,则单元格的成本将仅增加一个。
  • 在任何情况下,这些点都可以移出网格。

例子:

直觉:将左上角的点表示为point1 ,将右上角的点表示为point2 。以下是解决问题背后的直觉。

  • 请注意,它们的移动顺序无关紧要,因为它不会影响最终结果。最终成本取决于点的轨迹。因此,运动可以按任何顺序进行。有申请DP的需求,所以找一个适合DP的订单。在这里尝试一些可能的移动订单。
  • 将 DP 状态定义为(row1, col1, row2, col2) ,其中(row1, col1)表示point1的位置, (row2, col2)表示point2的位置。如果它们同步移动,则两个点将始终位于同一行。因此, row1 = row2
    row = row1 = row2 。 DP 状态被简化为(row, col1, col2) ,其中(row, col1)表示point1的位置, (row, col2)表示point2的位置。
  • 所以对于 DP函数:让dp(row, col1, col2)返回最大成本,如果point1(row, col1)开始并且point2(row, col2)开始。
  • 基本情况是两个点都从底线开始。在这种情况下,不需要移动,只考虑当前单元格的成本。如果点在完全相同的单元格处,请记住不要重复计算。
  • 在其他情况下,添加未来路径的最大成本。过渡函数来了。由于点可以同步移动,并且每个点在一个步骤中具有三种不同的运动,因此两个机器人总共有 3*3 = 9 种可能的运动:
Sl. No.Point1 movementPoint2 movement
1Left DownLeft Down
2Left DownDown
3Left DownRight Down
4DownLeft Down
5DownDown
6DownRight Down
7Right DownLeft Down
8Right DownDown
9Right DownRight Down
  • 未来路径的最大成本将是这 9 个动作中的最大值,即
    dp(row+1, new_col1, new_col2) ,其中new_col1可以是col1col1+1col1-1 ,而new_col2可以是col2col2+1col2-1

方法 1 – 动态规划(自下而上):问题解决方案基于动态规划概念并使用上述直觉。

  • 定义一个dp函数,它将三个整数row、col1 和 col2作为输入。
    • (row, col1)表示point1的位置, (row, col2)表示point2的位置。
    • 如果point1(row, col1)开始并且point2(row, col2)开始,则 dp函数返回最大成本。
  • dp函数中:
    • (row, col1)(row, col2)处添加成本。如果col1 = col2则不要重复计算。
    • 如果没有达到最后一行,则添加未来路径中可以获得的最大成本。
    • 未来能达到的最大代价是dp(row+1, new_col1, new_col2)的最大值,其中new_col1可以是col1, col1+1, or col1-1new_col2可以是col2, col2+1,或 col2-1
    • 返回总成本。
  • 最后,在 main函数中返回dp(row=0, col1=0, col2=last_column)

下面是上述方法的实现。

C++
// C++ code to implement the approach
#include 
using namespace std;
 
// Dp function
int dp(int row, int col1, int col2,
       vector >& grid,
       vector > >& dpCache)
{
    if (col1 < 0 || col1 >= grid[0].size()
        || col2 < 0 || col2 >= grid[0].size())
        return 0;
 
    // Check cache
    if (dpCache[row][col1][col2] != -1)
        return dpCache[row][col1][col2];
 
    // Add cost of the current cell
    int result = grid[row][col1];
    if (col1 != col2)
        result
            += grid[row][col2];
 
    // DP transition
    if (row != grid.size() - 1) {
        int maximum = 0;
        for (int newCol1 = col1 - 1;
             newCol1 <= col1 + 1; newCol1++)
            for (int newCol2 = col2 - 1;
                 newCol2 <= col2 + 1;
                 newCol2++)
                maximum
                    = max(maximum,
                          dp(row + 1, newCol1,
                             newCol2, grid,
                             dpCache));
 
        result += maximum;
    }
 
    dpCache[row][col1][col2] = result;
    return result;
}
 
// Function to maximize the cost
int pickup(vector >& grid)
{
    int M = grid.size();
    if (M == 0)
        return 0;
 
    int N = grid[0].size();
    if (N == 0)
        return 0;
 
    vector > >
    dpCache(M, vector >(
                   N, vector(N, -1)));
    return dp(0, 0, N - 1, grid, dpCache);
}
 
// Driver code
int main()
{
    vector > grid{
        { 3, 1, 1 }, { 2, 5, 1 },
        { 1, 5, 5 }, { 2, 1, 1 }
    };
    cout << pickup(grid);
    return 0;
}


Java
// Java code to implement the approach
import java.util.*;
 
class GFG{
  static int[][] grid = {
    { 3, 1, 1 }, { 2, 5, 1 },
    { 1, 5, 5 }, { 2, 1, 1 }
  };
  static int[][][] dpCache;
 
  // Dp function
  static int dp(int row, int col1, int col2)
  {
    if (col1 < 0 || col1 >= grid[0].length
        || col2 < 0 || col2 >= grid[0].length)
      return 0;
 
    // Check cache
    if (dpCache[row][col1][col2] != -1)
      return dpCache[row][col1][col2];
 
    // Add cost of the current cell
    int result = grid[row][col1];
    if (col1 != col2)
      result
      += grid[row][col2];
 
    // DP transition
    if (row != grid.length - 1) {
      int maximum = 0;
      for (int newCol1 = col1 - 1;
           newCol1 <= col1 + 1; newCol1++)
        for (int newCol2 = col2 - 1;
             newCol2 <= col2 + 1;
             newCol2++)
          maximum
          = Math.max(maximum,
                     dp(row + 1, newCol1,
                        newCol2));
 
      result += maximum;
    }
 
    dpCache[row][col1][col2] = result;
    return result;
  }
 
  // Function to maximize the cost
  static int pickup()
  {
    int M = grid.length;
    if (M == 0)
      return 0;
 
    int N = grid[0].length;
    if (N == 0)
      return 0;
 
 
 
    dpCache = new int[M][N][N];
    for(int i = 0; i < M; i++)
    {
      for(int j = 0; j < N; j++)
      {
        for(int l = 0; l < N; l++)
          dpCache[i][j][l] = -1;
      }
    }
    return dp(0, 0, N - 1);
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    System.out.print(pickup());
  }
}
 
// This code is contributed by Rajput-Ji


Python3
# python3 code to implement the approach
 
# Dp function
 
 
def dp(row, col1, col2, grid, dpCache):
 
    if (col1 < 0 or col1 >= len(grid[0])
            or col2 < 0 or col2 >= len(grid[0])):
        return 0
 
    # Check cache
    if (dpCache[row][col1][col2] != -1):
        return dpCache[row][col1][col2]
 
    # Add cost of the current cell
    result = grid[row][col1]
    if (col1 != col2):
        result += grid[row][col2]
 
    # DP transition
    if (row != len(grid) - 1):
        maximum = 0
        for newCol1 in range(col1-1, col1 + 2):
            for newCol2 in range(col2-1, col2+2):
                maximum = max(maximum,
                              dp(row + 1, newCol1,
                                 newCol2, grid,
                                 dpCache))
 
        result += maximum
 
    dpCache[row][col1][col2] = result
    return result
 
 
# Function to maximize the cost
def pickup(grid):
 
    M = len(grid)
    if (M == 0):
        return 0
 
    N = len(grid[0])
    if (N == 0):
        return 0
 
    dpCache = [[[-1 for _ in range(N)] for _ in range(N)] for _ in range(M)]
    return dp(0, 0, N - 1, grid, dpCache)
 
 
# Driver code
if __name__ == "__main__":
 
    grid = [
        [3, 1, 1], [2, 5, 1],
        [1, 5, 5], [2, 1, 1]
    ]
    print(pickup(grid))
 
# This code is contributed by rakeshsahni


Javascript


C++
// C++ code to implement the approach
#include 
using namespace std;
 
// Function to maximize the cost
int pickup(vector >& grid)
{
    int M = grid.size();
    if (M == 0)
        return 0;
 
    int N = grid[0].size();
    if (N == 0)
        return 0;
 
    vector > > dp(
        M, vector >(
               N, vector(N, INT_MIN)));
    dp[0][0][N - 1] = grid[0][0]
                      + grid[0][N - 1];
 
    for (int i = 1; i < M; i++)
        for (int a = 0; a < N; a++)
            for (int b = 0; b < N; b++)
                for (int l = a - 1; l
                                    <= a + 1;
                     l++)
                    for (int r = b - 1;
                         r <= b + 1; r++) {
                        if (l < 0 || l >= N
                            || r < 0
                            || r >= N)
                            continue;
 
                        dp[i][a][b] = max(
                            dp[i][a][b],
                            ((a != b)
                                 ? grid[i][a]
                                       + grid[i][b]
                                 : grid[i][a])
                                + dp[i - 1][l][r]);
                    }
     
  for (int i =0 ;i  > grid{
        { 3, 1, 1 }, { 2, 5, 1 },
        { 1, 5, 5 }, { 2, 1, 1 }
    };
    cout << pickup(grid);
    return 0;
}


Python3
# Python code to implement the approach
 
# Function to maximize the cost
import sys
 
def pickup(grid):
 
    M = len(grid)
    if (M == 0):
        return 0
 
    N = len(grid[0])
    if (N == 0):
        return 0
 
    dp = [[[(-sys.maxsize-1) for i in range(N)] for j in range(N)] for k in range(M)]
    dp[0][0][N - 1] = grid[0][0] + grid[0][N - 1]
 
    for i in range(1,M):
        for a in range(N):
            for b in range(N):
                for l in range(a - 1,a + 2):
                    for r in range(b - 1,b + 2):
                        if (l < 0 or l >= N or r < 0 or r >= N):
                            continue
 
                        dp[i][a][b] = max(dp[i][a][b],(grid[i][a]+ grid[i][b] if (a != b) else grid[i][a]) + dp[i - 1][l][r])
   
    ans = 0
    for a in range(N):
        for b in range(N):
            ans = max(ans, dp[M - 1][a][b])
    return ans
 
# Driver code
grid = [[ 3, 1, 1 ], [ 2, 5, 1 ],
        [ 1, 5, 5 ], [ 2, 1, 1 ]]
 
print(pickup(grid))
 
# This code is contributed by shinjanpatra


C#
// C# code to implement the approach
using System;
class GFG
{
   
  // Function to maximize the cost
  static int pickup(int[,] grid)
  {
    int M = grid.GetLength(0);
    if (M == 0)
      return 0;
 
    int N = grid.GetLength(1);
    if (N == 0)
      return 0;
 
    int [,,]dp = new int[M,N,N];
    dp[0,0,N - 1] = grid[0,0]
      + grid[0,N - 1];
 
    for (int i = 1; i < M; i++)
      for (int a = 0; a < N; a++)
        for (int b = 0; b < N; b++)
          for (int l = a - 1; l
               <= a + 1;
               l++)
            for (int r = b - 1;
                 r <= b + 1; r++) {
              if (l < 0 || l >= N
                  || r < 0
                  || r >= N)
                continue;
 
              dp[i,a,b] = Math.Max(
                dp[i,a,b],
                ((a != b)
                 ? grid[i,a]
                 + grid[i,b]
                 : grid[i,a])
                + dp[i - 1,l,r]);
            }
 
    int ans = 0;
    for (int a = 0; a < N; a++)
      for (int b = 0; b < N; b++)
        ans = Math.Max(ans, dp[M - 1,a,b]);
 
    return ans;
  }
 
  // Driver code
  public static void Main()
  {
    int[,] grid = {
      { 3, 1, 1 }, { 2, 5, 1 },
      { 1, 5, 5 }, { 2, 1, 1 }
    };
    Console.WriteLine( pickup(grid));
 
  }}
 
// This code is contributed by ukasp.


Javascript


C++
// C++ code to implement the approach
#include 
using namespace std;
 
// Function to maximize the cost
int pickup(vector >& grid)
{
    int M = grid.size();
    if (M == 0)
        return 0;
 
    int N = grid[0].size();
    if (N == 0)
        return 0;
 
    vector > > dp(
        2, vector >(
               N, vector(N, INT_MIN)));
    dp[0][0][N - 1] = grid[0][0]
                      + grid[0][N - 1];
 
    // Looping over all rows
    for (int i = 1; i < M; i++)
 
        // looping over every cell
        // in the row for point1
        for (int a = 0; a < N; a++)
 
            // looping over every cell
            // in the row for point2
            for (int b = 0; b < N; b++)
 
                // Capturing possible
                // movements of point 1
                for (int l = a - 1;
                     l <= a + 1; l++)
 
                    // Capturing possible
                    // movements of point2
                    for (int r = b - 1;
                         r <= b + 1; r++) {
                        if (l < 0 || l >= N
                            || r < 0 || r >= N)
                            continue;
 
                        // Apply DP transition
                        dp[i % 2][a][b] = max(
                            dp[i % 2][a][b],
                            ((a != b)
                                 ? grid[i][a]
                                       + grid[i][b]
                                 : grid[i][a])
                                + dp[(i - 1) % 2][l][r]);
                    }
 
    // Loop over dp to get the final answer
    int ans = 0;
    for (int a = 0; a < N; a++)
        for (int b = 0; b < N; b++)
            ans = max(ans,
                      dp[(M - 1) % 2][a][b]);
 
    return ans;
}
 
// Driver code
int main()
{
    vector > grid{
        { 3, 1, 1 }, { 2, 5, 1 },
        { 1, 5, 5 }, { 2, 1, 1 }
    };
    cout << pickup(grid);
    return 0;
}



输出
24

时间复杂度: O(M * N 2 )
辅助空间: O(M * N 2 )

方法 2 – 动态规划(自上而下):该解决方案也基于使用上述直觉的动态规划方法。唯一的区别是这里它使用了自顶向下的方法

  • 定义一个三维dp数组,其中每个维度的大小分别为 M、N 和 N,类似于方法 1。
  • 这里dp[row][col1][col2]表示在(row, col1)到达point1和在(row, col2)位置到达point2时的最大成本。
  • 计算 dp[row][col1][col2](转换方程):
    • 在 (row, col1) 和 (row, col2) 处添加成本。如果 col1 = col2,则不要重复计算。
    • 如果不在第一行,则添加已访问路径的最大成本。
  • 最后,返回最后一行的最大值。

注意:状态压缩可用于保存第一个维度: dp[col1][col2] 。只需在迭代一行后重用dp数组。

实现 1:无状态压缩

C++

// C++ code to implement the approach
#include 
using namespace std;
 
// Function to maximize the cost
int pickup(vector >& grid)
{
    int M = grid.size();
    if (M == 0)
        return 0;
 
    int N = grid[0].size();
    if (N == 0)
        return 0;
 
    vector > > dp(
        M, vector >(
               N, vector(N, INT_MIN)));
    dp[0][0][N - 1] = grid[0][0]
                      + grid[0][N - 1];
 
    for (int i = 1; i < M; i++)
        for (int a = 0; a < N; a++)
            for (int b = 0; b < N; b++)
                for (int l = a - 1; l
                                    <= a + 1;
                     l++)
                    for (int r = b - 1;
                         r <= b + 1; r++) {
                        if (l < 0 || l >= N
                            || r < 0
                            || r >= N)
                            continue;
 
                        dp[i][a][b] = max(
                            dp[i][a][b],
                            ((a != b)
                                 ? grid[i][a]
                                       + grid[i][b]
                                 : grid[i][a])
                                + dp[i - 1][l][r]);
                    }
     
  for (int i =0 ;i  > grid{
        { 3, 1, 1 }, { 2, 5, 1 },
        { 1, 5, 5 }, { 2, 1, 1 }
    };
    cout << pickup(grid);
    return 0;
}

Python3

# Python code to implement the approach
 
# Function to maximize the cost
import sys
 
def pickup(grid):
 
    M = len(grid)
    if (M == 0):
        return 0
 
    N = len(grid[0])
    if (N == 0):
        return 0
 
    dp = [[[(-sys.maxsize-1) for i in range(N)] for j in range(N)] for k in range(M)]
    dp[0][0][N - 1] = grid[0][0] + grid[0][N - 1]
 
    for i in range(1,M):
        for a in range(N):
            for b in range(N):
                for l in range(a - 1,a + 2):
                    for r in range(b - 1,b + 2):
                        if (l < 0 or l >= N or r < 0 or r >= N):
                            continue
 
                        dp[i][a][b] = max(dp[i][a][b],(grid[i][a]+ grid[i][b] if (a != b) else grid[i][a]) + dp[i - 1][l][r])
   
    ans = 0
    for a in range(N):
        for b in range(N):
            ans = max(ans, dp[M - 1][a][b])
    return ans
 
# Driver code
grid = [[ 3, 1, 1 ], [ 2, 5, 1 ],
        [ 1, 5, 5 ], [ 2, 1, 1 ]]
 
print(pickup(grid))
 
# This code is contributed by shinjanpatra

C#

// C# code to implement the approach
using System;
class GFG
{
   
  // Function to maximize the cost
  static int pickup(int[,] grid)
  {
    int M = grid.GetLength(0);
    if (M == 0)
      return 0;
 
    int N = grid.GetLength(1);
    if (N == 0)
      return 0;
 
    int [,,]dp = new int[M,N,N];
    dp[0,0,N - 1] = grid[0,0]
      + grid[0,N - 1];
 
    for (int i = 1; i < M; i++)
      for (int a = 0; a < N; a++)
        for (int b = 0; b < N; b++)
          for (int l = a - 1; l
               <= a + 1;
               l++)
            for (int r = b - 1;
                 r <= b + 1; r++) {
              if (l < 0 || l >= N
                  || r < 0
                  || r >= N)
                continue;
 
              dp[i,a,b] = Math.Max(
                dp[i,a,b],
                ((a != b)
                 ? grid[i,a]
                 + grid[i,b]
                 : grid[i,a])
                + dp[i - 1,l,r]);
            }
 
    int ans = 0;
    for (int a = 0; a < N; a++)
      for (int b = 0; b < N; b++)
        ans = Math.Max(ans, dp[M - 1,a,b]);
 
    return ans;
  }
 
  // Driver code
  public static void Main()
  {
    int[,] grid = {
      { 3, 1, 1 }, { 2, 5, 1 },
      { 1, 5, 5 }, { 2, 1, 1 }
    };
    Console.WriteLine( pickup(grid));
 
  }}
 
// This code is contributed by ukasp.

Javascript



输出
24

时间复杂度: O(M * N 2 )
辅助空间: O(M * N 2 )

实现 2:使用状态压缩

C++

// C++ code to implement the approach
#include 
using namespace std;
 
// Function to maximize the cost
int pickup(vector >& grid)
{
    int M = grid.size();
    if (M == 0)
        return 0;
 
    int N = grid[0].size();
    if (N == 0)
        return 0;
 
    vector > > dp(
        2, vector >(
               N, vector(N, INT_MIN)));
    dp[0][0][N - 1] = grid[0][0]
                      + grid[0][N - 1];
 
    // Looping over all rows
    for (int i = 1; i < M; i++)
 
        // looping over every cell
        // in the row for point1
        for (int a = 0; a < N; a++)
 
            // looping over every cell
            // in the row for point2
            for (int b = 0; b < N; b++)
 
                // Capturing possible
                // movements of point 1
                for (int l = a - 1;
                     l <= a + 1; l++)
 
                    // Capturing possible
                    // movements of point2
                    for (int r = b - 1;
                         r <= b + 1; r++) {
                        if (l < 0 || l >= N
                            || r < 0 || r >= N)
                            continue;
 
                        // Apply DP transition
                        dp[i % 2][a][b] = max(
                            dp[i % 2][a][b],
                            ((a != b)
                                 ? grid[i][a]
                                       + grid[i][b]
                                 : grid[i][a])
                                + dp[(i - 1) % 2][l][r]);
                    }
 
    // Loop over dp to get the final answer
    int ans = 0;
    for (int a = 0; a < N; a++)
        for (int b = 0; b < N; b++)
            ans = max(ans,
                      dp[(M - 1) % 2][a][b]);
 
    return ans;
}
 
// Driver code
int main()
{
    vector > grid{
        { 3, 1, 1 }, { 2, 5, 1 },
        { 1, 5, 5 }, { 2, 1, 1 }
    };
    cout << pickup(grid);
    return 0;
}


输出
24

时间复杂度: O(M * N 2 )
辅助空间: O(N 2 )