📌  相关文章
📜  到达目的地的最低初始点

📅  最后修改于: 2021-09-22 09:53:42             🧑  作者: Mango

给定一个网格,每个单元格由正、负或无点组成,即零点。只有当我们有正点 ( > 0 ) 时,我们才能在一个单元格中移动。每当我们通过一个单元格时,该单元格中的点都会添加到我们的总点数中。我们需要找到从 (0, 0) 到达单元格 (m-1, n-1) 的最小初始点。

约束:

  • 从单元格 (i, j) 我们可以移动到 (i+1, j) 或 (i, j+1)。
  • 如果您在 (i, j) 处的总点数 <= 0,则我们无法从 (i, j) 移动。
  • 我们必须以最小的正点到达 (n-1, m-1),即 > 0。

    例子:

    Input: points[m][n] = { {-2, -3,   3}, 
                            {-5, -10,  1}, 
                            {10,  30, -5} 
                          };
    Output: 7
    Explanation: 
    7 is the minimum value to reach destination with 
    positive throughout the path. Below is the path.
    
    (0,0) -> (0,1) -> (0,2) -> (1, 2) -> (2, 2)
    
    We start from (0, 0) with 7, we reach(0, 1) 
    with 5, (0, 2) with 2, (1, 2) with 5, (2, 2)
    with and finally we have 1 point (we needed 
    greater than 0 points at the end). 

    我们强烈建议您在继续解决方案之前单击此处进行练习。

    乍一看,这个问题看起来很像Max/Min Cost Path,但是获得的最大整体点数并不能保证最小的初始点数。此外,在当前问题中,分数永远不会降至零或以下是强制性的。例如,假设从源单元格到目标单元格存在以下两条路径。

    我们可以通过自底向上的填表动态规划技术来解决这个问题。

    • 首先,我们应该维护一个与网格大小相同的二维数组 dp,其中 dp[i][j] 表示在进入单元格 (i, j) 之前保证到达目的地的旅程继续的最小点。但很明显 dp[0][0] 是我们的最终解决方案。因此,对于这个问题,我们需要从右下角到左上角填充表格。
    • 现在,让我们决定离开单元格 (i, j) 所需的最小点(记住我们是从下往上移动)。只有两条路径可供选择:(i+1, j) 和 (i, j+1)。当然,我们会选择玩家可以以较小的初始点完成剩余旅程的单元格。因此我们有: min_Points_on_exit = min(dp[i+1][j], dp[i][j+1])

    现在我们知道如何计算 min_Points_on_exit,但是我们需要填充表 dp[][] 以获得 dp[0][0] 中的解。

    如何计算 dp[i][j]?
    dp[i][j] 的值可以写成如下。

    dp[i][j] = max(min_Points_on_exit – points[i][j], 1)

    让我们看看上面的表达式如何涵盖所有情况。

    • 如果 points[i][j] == 0,那么在这个单元格中什么也得不到;玩家可以在离开单元格时获得与他进入房间时相同的点数,即 dp[i][j] = min_Points_on_exit。
    • 如果 points[i][j] < 0,那么玩家在进入 (i, j) 之前必须拥有大于 min_Points_on_exit 的点数,以补偿在该单元格中丢失的点数。最小补偿量是“-points[i][j]”,所以我们有dp[i][j] = min_Points_on_exit-points[i][j]。
    • 如果 points[i][j] > 0,那么玩家可以输入 (i, j) 的点数为 min_Points_on_exit – points[i][j]。因为他可以在这个单元格中获得“points[i][j]”点。但是,在这种情况下,min_Points_on_exit – points[i][j] 的值可能会下降到 0 或更低。发生这种情况时,我们必须将该值裁剪为 1,以确保 dp[i][j] 保持正值:
      dp[i][j] = max(min_Points_on_exit – points[i][j], 1)。

    最后返回 dp[0][0] 这是我们的答案。

    下面是上述算法的实现。

    C++
    // C++ program to find minimum initial points to reach destination
    #include
    #define R 3
    #define C 3
      
    using namespace std;
      
    int minInitialPoints(int points[][C])
    {
        // dp[i][j] represents the minimum initial points player
        // should have so that when starts with cell(i, j) successfully
        // reaches the destination cell(m-1, n-1)
        int dp[R][C];
        int m = R, n = C;
      
        // Base case
        dp[m-1][n-1] = points[m-1][n-1] > 0? 1:
                       abs(points[m-1][n-1]) + 1;
      
        // Fill last row and last column as base to fill
        // entire table
        for (int i = m-2; i >= 0; i--)
             dp[i][n-1] = max(dp[i+1][n-1] - points[i][n-1], 1);
        for (int j = n-2; j >= 0; j--)
             dp[m-1][j] = max(dp[m-1][j+1] - points[m-1][j], 1);
      
        // fill the table in bottom-up fashion
        for (int i=m-2; i>=0; i--)
        {
            for (int j=n-2; j>=0; j--)
            {
                int min_points_on_exit = min(dp[i+1][j], dp[i][j+1]);
                dp[i][j] = max(min_points_on_exit - points[i][j], 1);
            }
         }
      
         return dp[0][0];
    }
      
    // Driver Program
    int main()
    {
      
        int points[R][C] = { {-2,-3,3},
                          {-5,-10,1},
                          {10,30,-5}
                        };
        cout << "Minimum Initial Points Required: "
             << minInitialPoints(points);
        return 0;
    }


    Java
    class min_steps
    {
        static int minInitialPoints(int points[][],int R,int C)
        {
            // dp[i][j] represents the minimum initial points player
            // should have so that when starts with cell(i, j) successfully
            // reaches the destination cell(m-1, n-1)
            int dp[][] = new int[R][C];
            int m = R, n = C;
           
            // Base case
            dp[m-1][n-1] = points[m-1][n-1] > 0? 1:
                           Math.abs(points[m-1][n-1]) + 1;
           
            // Fill last row and last column as base to fill
            // entire table
            for (int i = m-2; i >= 0; i--)
                 dp[i][n-1] = Math.max(dp[i+1][n-1] - points[i][n-1], 1);
            for (int j = n-2; j >= 0; j--)
                 dp[m-1][j] = Math.max(dp[m-1][j+1] - points[m-1][j], 1);
           
            // fill the table in bottom-up fashion
            for (int i=m-2; i>=0; i--)
            {
                for (int j=n-2; j>=0; j--)
                {
                    int min_points_on_exit = Math.min(dp[i+1][j], dp[i][j+1]);
                    dp[i][j] = Math.max(min_points_on_exit - points[i][j], 1);
                }
             }
           
             return dp[0][0];
        }
      
        /* Driver program to test above function */ 
        public static void main (String args[])
        {
              int points[][] = { {-2,-3,3},
                          {-5,-10,1},
                          {10,30,-5}
                        };
              int R = 3,C = 3;
              System.out.println("Minimum Initial Points Required: "+
                                                minInitialPoints(points,R,C) );
        }
    }/* This code is contributed by Rajat Mishra */


    Python3
    # Python3 program to find minimum initial
    # points to reach destination
    import math as mt
    R = 3
    C = 3
      
    def minInitialPoints(points):
        '''
        dp[i][j] represents the minimum initial
        points player should have so that when 
        starts with cell(i, j) successfully
        reaches the destination cell(m-1, n-1)
        '''
        dp = [[0 for x in range(C + 1)] 
                 for y in range(R + 1)]
        m, n = R, C
          
        if points[m - 1][n - 1] > 0:
            dp[m - 1][n - 1] = 1
        else:
            dp[m - 1][n - 1] = abs(points[m - 1][n - 1]) + 1
        '''
        Fill last row and last column as base
        to fill entire table
        '''
        for i in range (m - 2, -1, -1):
            dp[i][n - 1] = max(dp[i + 1][n - 1] -
                               points[i][n - 1], 1)
        for i in range (2, -1, -1):
            dp[m - 1][i] = max(dp[m - 1][i + 1] -
                               points[m - 1][i], 1)
        '''
        fill the table in bottom-up fashion
        '''
        for i in range(m - 2, -1, -1):
            for j in range(n - 2, -1, -1):
                min_points_on_exit = min(dp[i + 1][j],
                                         dp[i][j + 1])
                dp[i][j] = max(min_points_on_exit -
                                   points[i][j], 1)
                  
        return dp[0][0] 
          
    # Driver code
    points = [[-2, -3, 3],
              [-5, -10, 1],
              [10, 30, -5]]
      
    print("Minimum Initial Points Required:", 
                    minInitialPoints(points))
      
      
    # This code is contributed by 
    # Mohit kumar 29 (IIIT gwalior)


    C#
    // C# program Minimum Initial Points
    // to Reach Destination
    using System;
    class GFG {
          
        static int minInitialPoints(int [,]points, 
                                     int R, int C)
        {
              
            // dp[i][j] represents the 
            // minimum initial points 
            // player should have so 
            // that when starts with 
            // cell(i, j) successfully
            // reaches the destination
            // cell(m-1, n-1)
            int [,]dp = new int[R,C];
            int m = R, n = C;
          
            // Base case
            dp[m - 1,n - 1] = points[m - 1, n - 1] > 0 ? 1:
                         Math.Abs(points[m - 1,n - 1]) + 1;
          
            // Fill last row and last 
            // column as base to fill
            // entire table
            for (int i = m-2; i >= 0; i--)
                dp[i, n - 1] = Math.Max(dp[i + 1, n - 1] - 
                                    points[i, n - 1], 1);
            for (int j = n - 2; j >= 0; j--)
                dp[m - 1, j] = Math.Max(dp[m - 1, j + 1] - 
                                    points[m - 1, j], 1);
          
            // fill the table in 
            // bottom-up fashion
            for(int i = m - 2; i >= 0; i--)
            {
                for (int j = n - 2; j >= 0; j--)
                {
                    int min_points_on_exit = Math.Min(dp[i + 1, j], 
                                                      dp[i, j + 1]);
                    dp[i, j] = Math.Max(min_points_on_exit - 
                                          points[i, j], 1);
                }
            }
          
            return dp[0, 0];
        }
      
        // Driver Code
        public static void Main ()
        {
            int [,]points = {{-2,-3,3},
                             {-5,-10,1},
                               {10,30,-5}};
            int R = 3,C = 3;
            Console.Write("Minimum Initial Points Required: "+
                               minInitialPoints(points, R, C));
        }
    }
      
    // This code is contributed by nitin mittal.


    PHP
     0 ? 1 : 
                          abs($points[$m - 1][$n - 1]) + 1;
      
        // Fill last row and last column as 
        // base to fill entire table
        for ($i = $m - 2; $i >= 0; $i--)
            $dp[$i][$n - 1] = max($dp[$i + 1][$n - 1] - 
                                  $points[$i][$n - 1], 1);
        for ($j = $n - 2; $j >= 0; $j--)
            $dp[$m - 1][$j] = max($dp[$m - 1][$j + 1] - 
                                  $points[$m - 1][$j], 1);
      
        // fill the table in bottom-up fashion
        for ($i = $m - 2; $i >= 0; $i--)
        {
            for ($j = $n - 2; $j >= 0; $j--)
            {
                $min_points_on_exit = min($dp[$i + 1][$j], 
                                          $dp[$i][$j + 1]);
                $dp[$i][$j] = max($min_points_on_exit - 
                                  $points[$i][$j], 1);
            }
        }
      
        return $dp[0][0];
    }
      
    // Driver Code
    $points = array(array(-2, -3, 3),
                    array(-5, -10, 1),
                    array(10, 30, -5));
                  
    echo "Minimum Initial Points Required: ",
                   minInitialPoints($points);
      
    // This code is contributed by akt_mit
    ?>


    输出:

    Minimum Initial Points Required: 7

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