📜  骆驼和香蕉拼图 | DP

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

骆驼和香蕉拼图 | DP

一个人想把香蕉运送到公里外的目的地。他最初有B香蕉和骆驼。骆驼一次只能携带C根香蕉,每走一公里就要吃一根香蕉。给定三个整数ABC ,任务是找到一个人可以使用骆驼将香蕉转移到目的地的最大数量。

注意:给定的问题是著名的骆驼香蕉谜题的一般化版本。

例子:

方法:给定的问题可以通过使用记忆化的动态规划来解决,使用以下关键点:

  • 可以观察到,传输香蕉最有效的方法是将具有A km 的路径(u, v)分成一些更小的部分。假设x是路径(u, v)中的断点。最佳选择是将所有香蕉从u转移到x ,然后从x转移到v
  • 路径(u, v)中可以有任意数量的断点,使得断点的数量 < A
  • 如果CX因数, 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)