使用平方根或除以 2 将 A 和 B 减少到 0 的最小成本
给定两个整数 A 和 B,任务是通过执行以下两种类型的操作以最小的成本将给定的两个整数转换为零:
- 将整数 A 和 B 替换为 A 和 B 乘积的平方根。此操作将花费 2 个单位。
- 分别用 A/2 代替 A 或用 B/2 代替 B。此操作将花费 1 个单位。
例子:
Input: A = 2, B = 2
Output: 4
Explanation:
Operation 1: Apply first operation on A, making A=1, B=2. Cost=1
Operation 2: Apply first operation again on A, making A=0, B=2. Cost=2
Operation 3: Apply second operation on both A and B, making A=0, B=0. Cost=4.
Input: A = 53, B = 16
Output: 7
方法:
这个问题可以通过使用递归树探索所有可能性然后在矩阵中记忆解决方案来解决。要解决此问题,请执行以下步骤:
- 创建一个带有五个参数的函数getMinOperations ,它们是A、B、 prevA 、 prevB和一个dp 矩阵,这里prevA和prevB是A和B的先前值。此函数将返回使A和B为零所需的最小成本。
- 现在,首先使用参数A、B、prevA = -1、 prevB = -1 和dp调用此函数。
- 在每次通话中:
- 首先,检查A和B的值是否等于prevA和prevB的值。如果是,则从此调用返回 INT_MAX,因为此调用不会导致A和B的值发生变化,因此会导致无限递归循环。
- 检查A和B都为零的基本情况。如果是,则从此调用返回 0,因为在此阶段将A和B转换为零的最小成本为 0。
- 另外,检查这个递归调用是否已经存储在dp矩阵中。如果是,则从矩阵中返回值。
- 现在,每个递归调用的答案是三个子问题提供的答案中的最小值:
- 如果A减少到A/2 ,则成本最低。
- 如果B减少到B/2 ,则成本最低。
- 如果A和B都减少到sqrt(A*B) ,则成本最低。
- 找到这三个值中的最小值,并在从当前递归调用返回时将其记下来。
- 在进行所有递归调用后,该函数将返回最小成本。
下面是上述方法的实现:
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)