N层K栋楼上M个跳跃点的最大总和
给定K个有N层的建筑物和一个站在地上的人,最多可以跳M次。该人必须爬到顶部并收集最高分。如果该人可以爬上楼梯到同一建筑物的下一层,或者他可以跳到任何相邻建筑物的下一层,请找出可以收集的最大点数。
例子:
Input: N = 5, M = 2, K = 3,
points = [ [4, 5, 1, 2, 10],
[9, 7, 3, 20, 16],
[ 6, 12, 13, 9, 8] ]
Output: 70
Explanation: Start from building 2. Collect the 9 points in the first floor.
Jump to building 3. Collect the 12 points from the second and 13 points from third floor. (Jump 1)
Jump back to building 2. Collect the 20 points from fourth floor and 16 points in fifth floor. (Jump 2)
Number of jumps made = 2
Number of points collected= 9+12+13+20+16 = 70 points
Input: N = 4, M = 1, K = 3,
points = [ [7, 5, 4, 10],
[8, 9, 20, 16],
[ 12, 13, 3, 8] ]
Output: 61
方法:给定的问题可以使用动态规划来解决:
- 首先我们定义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)