骆驼和香蕉拼图 | DP
一个人想把香蕉运送到一公里外的目的地。他最初有B香蕉和骆驼。骆驼一次只能携带C根香蕉,每走一公里就要吃一根香蕉。给定三个整数A 、 B和C ,任务是找到一个人可以使用骆驼将香蕉转移到目的地的最大数量。
注意:给定的问题是著名的骆驼香蕉谜题的一般化版本。
例子:
Input: A = 10, B = 30, C = 10
Output: 5
Input: A = 1000, B = 3000, C = 1000
Output: 533
方法:给定的问题可以通过使用记忆化的动态规划来解决,使用以下关键点:
- 可以观察到,传输香蕉最有效的方法是将具有A km 的路径(u, v)分成一些更小的部分。假设x是路径(u, v)中的断点。最佳选择是将所有香蕉从u转移到x ,然后从x转移到v 。
- 路径(u, v)中可以有任意数量的断点,使得断点的数量 < A 。
- 如果C是X的因数(即, X % C = 0 ) 否则为2 * X / C +1 。
使用上述观察,可以通过以下步骤解决给定问题:
- 考虑一个 2D 数组dp[][] ,其中状态dp[A][B]表示一头骆驼在最初有B个香蕉的A km 距离内可以转移的香蕉的最大数量。用-1初始化dp[][]数组。
- 创建一个递归函数来迭代A km 的给定路径,并在每个有效索引处创建一个断点,并递归调用剩余路径的函数。
- 记住每个状态的最大香蕉数,如果当前状态已经计算,则返回记住的值。
下面是上述方法的实现:
C++
// C++ program of the above approach
#include
using namespace std;
// Stores the overlapping state
int dp[1001][3001];
// Recursive function to find the maximum
// number of bananas that can be transferred
// to A distance using memoization
int recBananaCnt(int A, int B, int C)
{
// Base Case where count of bananas
// is less that the given distance
if (B <= A) {
return 0;
}
// Base Case where count of bananas
// is less that camel's capacity
if (B <= C) {
return B - A;
}
// Base Case where distance = 0
if (A == 0) {
return B;
}
// If the current state is already
// calculated
if (dp[A][B] != -1) {
return dp[A][B];
}
// Stores the maximum count of bananas
int maxCount = INT_MIN;
// Stores the number of trips to transfer
// B bananas using a camel of capacity C
int tripCount = B % C == 0 ? ((2 * B) / C) - 1
: ((2 * B) / C) + 1;
// Loop to iterate over all the
// breakpoints in range [1, A]
for (int i = 1; i <= A; i++) {
// Recursive call over the
// remaining path
int curCount
= recBananaCnt(A - i,
B - tripCount * i, C);
// Update the maxCount
if (curCount > maxCount) {
maxCount = curCount;
// Memoize the current value
dp[A][B] = maxCount;
}
}
// Return answer
return maxCount;
}
// Function to find the maximum number of
// bananas that can be transferred
int maxBananaCnt(int A, int B, int C)
{
// Initialize dp array with -1
memset(dp, -1, sizeof(dp));
// Function Call
return recBananaCnt(A, B, C);
}
// Driver Code
int main()
{
int A = 1000;
int B = 3000;
int C = 1000;
cout << maxBananaCnt(A, B, C);
return 0;
}
Java
// Java program of the above approach
public class GFG {
// Stores the overlapping state
final static int dp[][] = new int[1001][3001];
// Recursive function to find the maximum
// number of bananas that can be transferred
// to A distance using memoization
static int recBananaCnt(int A, int B, int C)
{
// Base Case where count of bananas
// is less that the given distance
if (B <= A) {
return 0;
}
// Base Case where count of bananas
// is less that camel's capacity
if (B <= C) {
return B - A;
}
// Base Case where distance = 0
if (A == 0) {
return B;
}
// If the current state is already
// calculated
if (dp[A][B] != -1) {
return dp[A][B];
}
// Stores the maximum count of bananas
int maxCount = Integer.MIN_VALUE;
// Stores the number of trips to transfer
// B bananas using a camel of capacity C
int tripCount = B % C == 0 ? ((2 * B) / C) - 1 : ((2 * B) / C) + 1;
// Loop to iterate over all the
// breakpoints in range [1, A]
for (int i = 1; i <= A; i++) {
// Recursive call over the
// remaining path
int curCount
= recBananaCnt(A - i,
B - tripCount * i, C);
// Update the maxCount
if (curCount > maxCount) {
maxCount = curCount;
// Memoize the current value
dp[A][B] = maxCount;
}
}
// Return answer
return maxCount;
}
// Function to find the maximum number of
// bananas that can be transferred
static int maxBananaCnt(int A, int B, int C)
{
// Initialize dp array with -1
for(int i = 0; i < 1001; i++)
for (int j = 0; j < 3001; j++)
dp[i][j] = -1;
// Function Call
return recBananaCnt(A, B, C);
}
// Driver Code
public static void main (String[] args) {
int A = 1000;
int B = 3000;
int C = 1000;
System.out.println(maxBananaCnt(A, B, C));
}
}
// This code is contributed by AnkThon
Python3
# Python program of the above approach
# Stores the overlapping state
dp = [[-1 for i in range(3001)] for j in range(1001)]
# Recursive function to find the maximum
# number of bananas that can be transferred
# to A distance using memoization
def recBananaCnt(A, B, C):
# Base Case where count of bananas
# is less that the given distance
if (B <= A):
return 0
# Base Case where count of bananas
# is less that camel's capacity
if (B <= C):
return B - A
# Base Case where distance = 0
if (A == 0):
return B
# If the current state is already
# calculated
if (dp[A][B] != -1):
return dp[A][B]
# Stores the maximum count of bananas
maxCount = -2**32
# Stores the number of trips to transfer
# B bananas using a camel of capacity C
tripCount = ((2 * B) // C) - 1 if(B % C == 0 ) else ((2 * B) // C) + 1
# Loop to iterate over all the
# breakpoints in range [1, A]
for i in range(1,A+1):
# Recursive call over the
# remaining path
curCount = recBananaCnt(A - i, B - tripCount * i, C)
# Update the maxCount
if (curCount > maxCount):
maxCount = curCount
# Memoize the current value
dp[A][B] = maxCount
# Return answer
return maxCount
# Function to find the maximum number of
# bananas that can be transferred
def maxBananaCnt(A, B, C):
# Function Call
return recBananaCnt(A, B, C)
# Driver Code
A = 1000
B = 3000
C = 1000
print(maxBananaCnt(A, B, C))
# This code is contributed by shivanisinghss2110
C#
// C# program of the above approach
using System;
public class GFG {
// Stores the overlapping state
static int[, ] dp = new int[1001, 3001];
// Recursive function to find the maximum
// number of bananas that can be transferred
// to A distance using memoization
static int recBananaCnt(int A, int B, int C)
{
// Base Case where count of bananas
// is less that the given distance
if (B <= A) {
return 0;
}
// Base Case where count of bananas
// is less that camel's capacity
if (B <= C) {
return B - A;
}
// Base Case where distance = 0
if (A == 0) {
return B;
}
// If the current state is already
// calculated
if (dp[A, B] != -1) {
return dp[A, B];
}
// Stores the maximum count of bananas
int maxCount = Int32.MinValue;
// Stores the number of trips to transfer
// B bananas using a camel of capacity C
int tripCount = B % C == 0 ? ((2 * B) / C) - 1
: ((2 * B) / C) + 1;
// Loop to iterate over all the
// breakpoints in range [1, A]
for (int i = 1; i <= A; i++) {
// Recursive call over the
// remaining path
int curCount
= recBananaCnt(A - i, B - tripCount * i, C);
// Update the maxCount
if (curCount > maxCount) {
maxCount = curCount;
// Memoize the current value
dp[A, B] = maxCount;
}
}
// Return answer
return maxCount;
}
// Function to find the maximum number of
// bananas that can be transferred
static int maxBananaCnt(int A, int B, int C)
{
// Initialize dp array with -1
for (int i = 0; i < 1001; i++)
for (int j = 0; j < 3001; j++)
dp[i, j] = -1;
// Function Call
return recBananaCnt(A, B, C);
}
// Driver Code
public static void Main(string[] args)
{
int A = 1000;
int B = 3000;
int C = 1000;
Console.WriteLine(maxBananaCnt(A, B, C));
}
}
// This code is contributed by ukasp.
Javascript
输出:
533
时间复杂度: O(A*A*B)
辅助空间: O(A*B)