📜  使用平方根或除以 2 将 A 和 B 减少到 0 的最小成本

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

使用平方根或除以 2 将 A 和 B 减少到 0 的最小成本

给定两个整数 A 和 B,任务是通过执行以下两种类型的操作以最小的成本将给定的两个整数转换为零:

  • 将整数 A 和 B 替换为 A 和 B 乘积的平方根。此操作将花费 2 个单位。
  • 分别用 A/2 代替 A 或用 B/2 代替 B。此操作将花费 1 个单位。

例子:

方法:

这个问题可以通过使用递归树探索所有可能性然后在矩阵中记忆解决方案来解决。要解决此问题,请执行以下步骤:

  1. 创建一个带有五个参数的函数getMinOperations ,它们是A、B、 prevAprevB和一个dp 矩阵,这里prevAprevBAB的先前值。此函数将返回使AB为零所需的最小成本。
  2. 现在,首先使用参数A、B、prevA = -1、 prevB = -1 和dp调用此函数。
  3. 在每次通话中:
    • 首先,检查AB的值是否等于prevAprevB的值。如果是,则从此调用返回 INT_MAX,因为此调用不会导致AB的值发生变化,因此会导致无限递归循环。
    • 检查AB都为零的基本情况。如果是,则从此调用返回 0,因为在此阶段将AB转换为零的最小成本为 0。
    • 另外,检查这个递归调用是否已经存储在dp矩阵中。如果是,则从矩阵中返回值。
    • 现在,每个递归调用的答案是三个子问题提供的答案中的最小值:
      • 如果A减少到A/2 ,则成本最低。
      • 如果B减少到B/2 ,则成本最低。
      • 如果AB都减少到sqrt(A*B) ,则成本最低。
    • 找到这三个值中的最小值,并在从当前递归调用返回时将其记下来。
  4. 在进行所有递归调用后,该函数将返回最小成本。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
 
// Function to return the minimum cost
// of converting A and B to 0
int getMinOperations(int A, int B,
                     int prevA, int prevB,
                     vector >& dp)
{
 
    // If both A and B doesn't change in
    // this recursive call, then return INT_MAX
    // to save the code from going into
    // infinite loop
    if (A == prevA and B == prevB) {
        return INT_MAX;
    }
 
    // Base Case
    if (A == 0 and B == 0) {
        return 0;
    }
 
    // If the answer of this recursive call
    // is already memoised
    if (dp[A][B] != -1) {
        return dp[A][B];
    }
 
    // If A is reduced to A/2
    int ans1 = getMinOperations(
        A / 2, B, A, B, dp);
    if (ans1 != INT_MAX) {
        ans1 += 1;
    }
 
    // If B is reduced to B/2
    int ans2 = getMinOperations(
        A, B / 2, A, B, dp);
    if (ans2 != INT_MAX) {
        ans2 += 1;
    }
 
    // If both A and B is reduced to sqrt(A * B)
    int ans3 = getMinOperations(sqrt(A * B),
                                sqrt(A * B), A,
                                B, dp);
    if (ans3 != INT_MAX) {
        ans3 += 2;
    }
 
    // Return the minimum of the value given
    // by the above three subproblems, also
    // memoize the value while returning
    return dp[A][B] = min({ ans1, ans2, ans3 });
}
 
// Driver Code
int main()
{
    int A = 53, B = 16;
    int mx = max(A, B);
    vector > dp(
        mx + 1,
        vector(mx + 1, -1));
 
    cout << getMinOperations(
        A, B, -1, -1, dp);
}


Java
// Java program for the above approach
import java.io.*;
class GFG
{
   
    // Function to return the minimum cost
    // of converting A and B to 0
    static int getMinOperations(int A, int B, int prevA,
                                int prevB, int dp[][])
    {
 
        // If both A and B doesn't change in
        // this recursive call, then return INT_MAX
        // to save the code from going into
        // infinite loop
        if (A == prevA && B == prevB) {
            return Integer.MAX_VALUE;
        }
 
        // Base Case
        if (A == 0 && B == 0) {
            return 0;
        }
 
        // If the answer of this recursive call
        // is already memoised
        if (dp[A][B] != -1) {
            return dp[A][B];
        }
 
        // If A is reduced to A/2
        int ans1 = getMinOperations(A / 2, B, A, B, dp);
        if (ans1 != Integer.MAX_VALUE) {
            ans1 += 1;
        }
 
        // If B is reduced to B/2
        int ans2 = getMinOperations(A, B / 2, A, B, dp);
        if (ans2 != Integer.MAX_VALUE) {
            ans2 += 1;
        }
 
        // If both A and B is reduced to sqrt(A * B)
        int ans3 = getMinOperations((int)Math.sqrt(A * B),
                                    (int)Math.sqrt(A * B),
                                    A, B, dp);
        if (ans3 != Integer.MAX_VALUE) {
            ans3 += 2;
        }
        // Return the minimum of the value given
        // by the above three subproblems, also
        // memoize the value while returning
        return dp[A][B]
            = Math.min(ans1, Math.min(ans2, ans3));
    }
   
    // Driver Code
    public static void main(String[] args)
    {
        int A = 53, B = 16;
        int mx = Math.max(A, B);
        int dp[][] = new int[mx + 1][mx + 1];
        for (int i = 0; i <= mx; i++) {
            for (int j = 0; j <= mx; j++)
                dp[i][j] = -1;
        }
        System.out.println(
            getMinOperations(A, B, -1, -1, dp));
    }
}
 
// This code is contributed by dwivediyash


Python3
# Python program for the above approach
import math as Math
 
# Function to return the minimum cost
# of converting A and B to 0
def getMinOperations(A, B, prevA, prevB, dp):
   
  # If both A and B doesn't change in
  # this recursive call, then return INT_MAX
  # to save the code from going into
  # infinite loop
  if (A == prevA and B == prevB):
    return 10**9;
   
  # Base Case
  if (A == 0 and B == 0):
    return 0;
   
  # If the answer of this recursive call
  # is already memoised
  if (dp[A][B] != -1):
    return dp[A][B];
   
  # If A is reduced to A/2
  ans1 = getMinOperations(A // 2, B, A, B, dp);
  if (ans1 != 10**9):
    ans1 += 1;
   
  # If B is reduced to B/2
  ans2 = getMinOperations(A, B // 2, A, B, dp);
  if (ans2 != 10**9):
    ans2 += 1;
   
  # If both A and B is reduced to sqrt(A * B)
  ans3 = getMinOperations(
    Math.floor(Math.sqrt(A * B)),
    Math.floor(Math.sqrt(A * B)),
    A,
    B,
    dp
  );
  if (ans3 != 10**9):
    ans3 += 2;
   
  # Return the minimum of the value given
  # by the above three subproblems, also
  # memoize the value while returning
  dp[A][B] = min(ans1, min(ans2, ans3))
  return dp[A][B];
 
# Driver Code
A = 53
B = 16
mx = max(A, B);
dp = [[-1 for i in range(mx + 1)] for i in range(mx + 1)]
 
print(getMinOperations(A, B, -1, -1, dp));
 
# This code is contributed by gfgking.


C#
// C# program for the above approach
using System;
using System.Collections;
class GFG
{
   
    // Function to return the minimum cost
    // of converting A and B to 0
    static int getMinOperations(int A, int B, int prevA,
                                int prevB, int [,]dp)
    {
 
        // If both A and B doesn't change in
        // this recursive call, then return INT_MAX
        // to save the code from going into
        // infinite loop
        if (A == prevA && B == prevB) {
            return Int32.MaxValue;
        }
 
        // Base Case
        if (A == 0 && B == 0) {
            return 0;
        }
 
        // If the answer of this recursive call
        // is already memoised
        if (dp[A, B] != -1) {
            return dp[A, B];
        }
 
        // If A is reduced to A/2
        int ans1 = getMinOperations(A / 2, B, A, B, dp);
        if (ans1 != Int32.MaxValue) {
            ans1 += 1;
        }
 
        // If B is reduced to B/2
        int ans2 = getMinOperations(A, B / 2, A, B, dp);
        if (ans2 != Int32.MaxValue) {
            ans2 += 1;
        }
 
        // If both A and B is reduced to sqrt(A * B)
        int ans3 = getMinOperations((int)Math.Sqrt(A * B),
                                    (int)Math.Sqrt(A * B),
                                    A, B, dp);
        if (ans3 != Int32.MaxValue) {
            ans3 += 2;
        }
        // Return the minimum of the value given
        // by the above three subproblems, also
        // memoize the value while returning
        return dp[A, B]
            = Math.Min(ans1, Math.Min(ans2, ans3));
    }
   
    // Driver Code
    public static void Main()
    {
        int A = 53, B = 16;
        int mx = Math.Max(A, B);
        int [,]dp = new int[mx + 1, mx + 1];
        for (int i = 0; i <= mx; i++) {
            for (int j = 0; j <= mx; j++)
                dp[i, j] = -1;
        }
        Console.Write(
            getMinOperations(A, B, -1, -1, dp));
    }
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript


输出
7

时间复杂度: O(max(A, B)^2)
辅助空间: O(max(A, B)^2)