📌  相关文章
📜  N层K栋楼上M个跳跃点的最大总和

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

N层K栋楼上M个跳跃点的最大总和

给定K个有N层的建筑物和一个站在地上的人,最多可以跳M次。该人必须爬到顶部并收集最高分。如果该人可以爬上楼梯到同一建筑物的下一层,或者他可以跳到任何相邻建筑物的下一层,请找出可以收集的最大点数。

例子:

方法:给定的问题可以使用动态规划来解决:

  • 首先我们定义dp的状态
    • dp(i, j, k) 状态——如果人在第i层,最多进行了j次跳跃并最终到达第k层建筑物,则可以收集的最大点数
  • 然后我们将定义基本情况
    • 如果只有一层那么这个人不能跳,把点数放在那个位置。
    • 如果允许 0 次跳跃,则可以选择三座建筑物之一并继续爬上同一座建筑物。
    • 所以,这个人只能从同一栋楼的上一层拿积分并添加当前积分
  • 然后我们将定义状态之间的转换
  • 如果我们在第一个建筑物上,那么我们可以:
    • 来自第一栋楼,向下一层,没有跳跃
    • 来自隔壁楼,下一层,加一跳
  • 为这两种情况添加存储在第 1 楼第 1 层的点
  • 如果我们在中间建筑,那么我们可以:
    • 来自上一栋楼,下一层,加一跳
    • 来自当前楼,下一层,不跳
    • 可以从隔壁楼来,下一层,加一跳
  • 将为所有 3 个案例添加存储在第 1 层中间建筑物中的积分
  • 如果我们在最后一栋楼,那么我们可以:
    • 来自上一栋楼,下一层,加一跳
    • 来自最后一栋楼,向下一层,没有添加跳跃
  • 将在这两种情况下添加存储在最后一栋建筑物中的点数
  • 对于最终答案,在进行允许的跳跃次数后,返回在所有建筑物的顶层收集的最大分数。

下面是上述方法的实现:

C++14
// C++ implementation for the above approach
 
#include 
using namespace std;
 
int solve(vector >& a, int floors,
          int jumps, int buildings)
{
    /*
     dp(i, j, k) represents state of the maximum
     number of points that can be collected if
     the person is at ith floor having made at
     most j jumps and ended up at kth building.
    */
    int dp[floors + 1][jumps + 1][buildings + 1];
 
    // Initializing dp with 0
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= floors; i++) {
        for (int j = 0; j <= jumps; j++) {
            for (int k = 0; k < buildings; k++) {
 
                // Base case: first floor
                if (i == 1) {
                    // Cannot jump on ground floor
                    // from any other building
                    dp[i][j][k] = a[k][i - 1];
                }
 
                // Base case: no jumps allowed
                else if (j == 0) {
 
                    /* can choose one of the buildings
                    and keep climbing up on the
                    same building so can only take
                    points from prev floor of same
                    building and add current points
                 */
                    dp[i][j][k] = dp[i - 1][j][k]
                                  + a[k][i - 1];
                }
 
                // transition
                else {
 
                    // first building
                    if (k == 0) {
 
                        /*
                        1)can come from building 1,
                        one floor down, no jumps.
                        2)can come from building 2,
                        one floor down, one jump added.
                        add points stored in building 1
                        at the ith floor for both cases.
                        */
                        dp[i][j][k] = max(dp[i - 1][j][k],
                                          dp[i - 1][j - 1][k + 1])
                                      + a[k][i - 1];
                    }
 
                    // Last Building
                    else if (k == buildings - 1) {
 
                        /*
                       1)Can come from building k-1 from
                         one floor below, one jump added.
                       2)Can come from building k from
                        one floor below, no jump added.
                        add points stored in building k
                        at the ith floor for both cases.
                            */
                        dp[i][j][k]
                            = max(
                                  dp[i - 1][j - 1][k - 1],
                                  dp[i - 1][j][k])
                              + a[k][i - 1];
                    }
 
                    // intermediate buildings
                    else {
 
                        /*
                        1)Can come from the building k-1,
                        one floor down, one jump added
                        2)Can come from the building k,
                        one floor down, no jump
                        3)Can come from the building k+1,
                        one floor down, one jump added.
                        add points stored in building k
                        at the ith floor for all 3 cases
                        */
                        dp[i][j][k]
                            = max(
                                  { dp[i - 1][j - 1][k - 1],
                                    dp[i - 1][j][k],
                                    dp[i - 1][j - 1][k + 1] })
                              + a[k][i - 1];
                    }
                }
            }
        }
    }
 
    // Return the maximum of points collected
    // over the top floor of all building after
    // engaging in permissible number of jumps
    int ans = 0;
    for (int building = 0; building < buildings; building++)
        ans = max(ans, dp[floors][jumps][building]);
 
    return ans;
}
 
// Driver code
int main()
{
    // Number of floors
    // and number of jumps allowed.
    int N = 5, M = 2, K = 3;
 
    // Number of points
    // at each floor of the buildings.
    vector > a = {
        { 4, 5, 1, 2, 10 },
        { 9, 7, 3, 20, 16 },
        { 6, 12, 13, 9, 8 }
    };
 
    // Function call
    cout << solve(a, N, M, K) << endl;
 
    return 0;
}


Java
// Java implementation for the above approach
import java.util.*;
 
class GFG
{
 
  static int solve(int[][] a, int floors,
                   int jumps, int buildings)
  {
    /*
     dp(i, j, k) represents state of the maximum
     number of points that can be collected if
     the person is at ith floor having made at
     most j jumps and ended up at kth building.
    */
    int [][][]dp = new int[floors + 1][jumps + 1][buildings + 1];
 
    for (int i = 1; i <= floors; i++) {
      for (int j = 0; j <= jumps; j++) {
        for (int k = 0; k < buildings; k++) {
 
          // Base case: first floor
          if (i == 1) {
            // Cannot jump on ground floor
            // from any other building
            dp[i][j][k] = a[k][i - 1];
          }
 
          // Base case: no jumps allowed
          else if (j == 0) {
 
            /* can choose one of the buildings
                    and keep climbing up on the
                    same building so can only take
                    points from prev floor of same
                    building and add current points
                 */
            dp[i][j][k] = dp[i - 1][j][k]
              + a[k][i - 1];
          }
 
          // transition
          else {
 
            // first building
            if (k == 0) {
 
              /*
                        1)can come from building 1,
                        one floor down, no jumps.
                        2)can come from building 2,
                        one floor down, one jump added.
                        add points stored in building 1
                        at the ith floor for both cases.
                        */
              dp[i][j][k] = Math.max(dp[i - 1][j][k],
                                     dp[i - 1][j - 1][k + 1])
                + a[k][i - 1];
            }
 
            // Last Building
            else if (k == buildings - 1) {
 
              /*
                       1)Can come from building k-1 from
                         one floor below, one jump added.
                       2)Can come from building k from
                        one floor below, no jump added.
                        add points stored in building k
                        at the ith floor for both cases.
                            */
              dp[i][j][k]
                = Math.max(
                dp[i - 1][j - 1][k - 1],
                dp[i - 1][j][k])
                + a[k][i - 1];
            }
 
            // intermediate buildings
            else {
 
              /*
                        1)Can come from the building k-1,
                        one floor down, one jump added
                        2)Can come from the building k,
                        one floor down, no jump
                        3)Can come from the building k+1,
                        one floor down, one jump added.
                        add points stored in building k
                        at the ith floor for all 3 cases
                        */
              dp[i][j][k]
                = Math.max(
                Math.max( dp[i - 1][j - 1][k - 1],
                         dp[i - 1][j][k]),
                dp[i - 1][j - 1][k + 1] )
                + a[k][i - 1];
            }
          }
        }
      }
    }
 
    // Return the maximum of points collected
    // over the top floor of all building after
    // engaging in permissible number of jumps
    int ans = 0;
    for (int building = 0; building < buildings; building++)
      ans = Math.max(ans, dp[floors][jumps][building]);
 
    return ans;
  }
 
  // Driver code
  public static void main(String[] args)
  {
     
    // Number of floors
    // and number of jumps allowed.
    int N = 5, M = 2, K = 3;
 
    // Number of points
    // at each floor of the buildings.
    int[][] a = {
      { 4, 5, 1, 2, 10 },
      { 9, 7, 3, 20, 16 },
      { 6, 12, 13, 9, 8 }
    };
 
    // Function call
    System.out.print(solve(a, N, M, K) +"\n");
 
  }
}
 
// This code is contributed by Princi Singh


Python3
# Python 3 implementation for the above approach
 
def solve(a, floors, jumps, buildings):
   
    #dp(i, j, k) represents state of the maximum
    #number of points that can be collected if
    #the person is at ith floor having made at
    #most j jumps and ended up at kth building.
    dp = [[[0 for i in range(buildings + 1)] for j in range(jumps + 1)] for k in range(floors + 1)]
 
    for i in range(1, floors + 1, 1):
        for j in range(0, jumps + 1, 1):
            for k in range(buildings):
               
                # Base case: first floor
                if (i == 1):
                   
                    # Cannot jump on ground floor
                    # from any other building
                    dp[i][j][k] = a[k][i - 1]
 
                # Base case: no jumps allowed
                elif(j == 0):
                   
                    # can choose one of the buildings
                    # and keep climbing up on the
                    # same building so can only take
                    # points from prev floor of same
                    # building and add current points
                    dp[i][j][k] = dp[i - 1][j][k] + a[k][i - 1]
 
                # transition
                else:
 
                    # first building
                    if (k == 0):
                        # 1)can come from building 1,
                        # one floor down, no jumps.
                        # 2)can come from building 2,
                        # one floor down, one jump added.
                        # add points stored in building 1
                        # at the ith floor for both cases.
                        dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - 1][k + 1]) + a[k][i - 1]
 
                    # Last Building
                    elif(k == buildings - 1):
                        # 1)Can come from building k-1 from
                        # one floor below, one jump added.
                        # 2)Can come from building k from
                        # one floor below, no jump added.
                        # add points stored in building k
                        # at the ith floor for both cases.
                        dp[i][j][k] = max(dp[i - 1][j - 1][k - 1],dp[i - 1][j][k]) + a[k][i - 1]
 
                    # intermediate buildings
                    else:
                        # 1)Can come from the building k-1,
                        # one floor down, one jump added
                        # 2)Can come from the building k,
                        # one floor down, no jump
                        # 3)Can come from the building k+1,
                        # one floor down, one jump added.
                        # add points stored in building k
                        # at the ith floor for all 3 cases
                        dp[i][j][k] = max([dp[i - 1][j - 1][k - 1],dp[i - 1][j][k],dp[i - 1][j - 1][k + 1]])+ a[k][i - 1]
 
    # Return the maximum of points collected
    # over the top floor of all building after
    # engaging in permissible number of jumps
    ans = 0
    for temp in range(buildings):
        ans = max(ans, dp[floors][jumps][temp])
 
    return ans
 
# Driver code
if __name__ == '__main__':
   
    # Number of floors
    # and number of jumps allowed.
    N = 5
    M = 2
    K = 3
 
    # Number of points
    # at each floor of the buildings.
    a = [[4, 5, 1, 2, 10],
         [9, 7, 3, 20, 16],
         [6, 12, 13, 9, 8]]
 
    # Function call
    print(solve(a, N, M, K))
     
    # This code is contributed by ipg2016107.


C#
// C# implementation for the above approach
using System;
 
class GFG
{
 
  static int solve(int[,] a, int floors,
                   int jumps, int buildings)
  {
    /*
     dp(i, j, k) represents state of the maximum
     number of points that can be collected if
     the person is at ith floor having made at
     most j jumps and ended up at kth building.
    */
    int [,,]dp = new int[floors + 1,jumps + 1,buildings + 1];
 
    for (int i = 1; i <= floors; i++) {
      for (int j = 0; j <= jumps; j++) {
        for (int k = 0; k < buildings; k++) {
 
          // Base case: first floor
          if (i == 1)
          {
             
            // Cannot jump on ground floor
            // from any other building
            dp[i, j, k] = a[k, i - 1];
          }
 
          // Base case: no jumps allowed
          else if (j == 0) {
 
            /* can choose one of the buildings
                    and keep climbing up on the
                    same building so can only take
                    points from prev floor of same
                    building and add current points
                 */
            dp[i, j, k] = dp[i - 1, j, k]
              + a[k, i - 1];
          }
 
          // transition
          else {
 
            // first building
            if (k == 0) {
 
              /*
                        1)can come from building 1,
                        one floor down, no jumps.
                        2)can come from building 2,
                        one floor down, one jump added.
                        add points stored in building 1
                        at the ith floor for both cases.
                        */
              dp[i, j, k] = Math.Max(dp[i - 1, j, k],
                                     dp[i - 1, j - 1, k + 1])
                + a[k,i - 1];
            }
 
            // Last Building
            else if (k == buildings - 1) {
 
              /*
                       1)Can come from building k-1 from
                         one floor below, one jump added.
                       2)Can come from building k from
                        one floor below, no jump added.
                        add points stored in building k
                        at the ith floor for both cases.
                            */
              dp[i, j, k]
                = Math.Max(
                dp[i - 1,j - 1,k - 1],
                dp[i - 1,j,k])
                + a[k,i - 1];
            }
 
            // intermediate buildings
            else {
 
              /*
                        1)Can come from the building k-1,
                        one floor down, one jump added
                        2)Can come from the building k,
                        one floor down, no jump
                        3)Can come from the building k+1,
                        one floor down, one jump added.
                        add points stored in building k
                        at the ith floor for all 3 cases
                        */
              dp[i, j, k]
                = Math.Max(
                Math.Max( dp[i - 1, j - 1, k - 1],
                         dp[i - 1, j, k]),
                dp[i - 1, j - 1, k + 1] )
                + a[k, i - 1];
            }
          }
        }
      }
    }
 
    // Return the maximum of points collected
    // over the top floor of all building after
    // engaging in permissible number of jumps
    int ans = 0;
    for (int building = 0; building < buildings; building++)
      ans = Math.Max(ans, dp[floors,jumps,building]);
 
    return ans;
  }
 
  // Driver code
  public static void Main(string[] args)
  {
     
    // Number of floors
    // and number of jumps allowed.
    int N = 5, M = 2, K = 3;
 
    // Number of points
    // at each floor of the buildings.
    int[,] a = {
      { 4, 5, 1, 2, 10 },
      { 9, 7, 3, 20, 16 },
      { 6, 12, 13, 9, 8 }
    };
 
    // Function call
    Console.WriteLine(solve(a, N, M, K));
 
  }
}
 
// This code is contributed by AnkThon


Javascript


输出:
70

时间复杂度: O(N*M*K) 这意味着 O(floors*jumps*buildings)
辅助空间: O(N*M*K) 这意味着 O(floors*jumps*buildings)