Open In App

Minimum cost to reduce A and B to 0 using square root or divide by 2

Last Updated : 07 Jul, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two integers A and B, the task is to convert the given two integers to zero at minimal cost by performing the following two types of operations: 

  • Replace both integers A and B by the square root of the product of A and B. This operation will cost 2 units.
  • Replace A by A/2 or B by B/2 respectively. This operation will cost 1 unit.

Example:

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

 

Approach:

This problem can be solved by exploring all possibilities using a recursive tree and then memoizing the solution in a matrix. To solve this problem follow the below steps:

  1. Create a function getMinOperations with five parameters that are A, B,   prevA, prevB, and a dp matrix, here prevA and prevB are the previous value of A and B. This function will return the minimum cost required to make A and B to zero.
  2. Now, call this function initially with arguments, A, B, prevA = -1, prevB = -1 and dp.
  3. In each call:
    • First, check if the value of A and B is equal to the value of prevA and prevB. If they are, return INT_MAX from this call as this call is resulting in no change in the values of A and B and therefore will resulting in an infinite recursive loop.
    • Check for the base case that is both A and B are zero. If they are, return 0 from this call because the minimum cost to convert A and B to zero is 0 at this stage.
    • Also, check if this recursive call is already memorized in the dp matrix. If it is, then return the value from the matrix.
    • Now, the answer of every recursive call is the minimum of the answers provided by three subproblems:
      • Minimum cost if A is reduced to A/2.
      • Minimum cost if B is reduced to B/2.
      • Minimum cost if both A and B is reduced to sqrt(A*B).
    • Find the minimum of these three values and memoize it while returning from the current recursive call.
  4. The function will return the minimum cost after all recursive calls are made.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
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<vector<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 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<vector<int> > dp(
        mx + 1,
        vector<int>(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




<script>
// javascript program for the above approach
 
// Function to return the minimum cost
// of converting A and B to 0
function 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 && B == prevB) {
    return Number.MAX_SAFE_INTEGER;
  }
 
  // 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
  let ans1 = getMinOperations(Math.floor(A / 2), B, A, B, dp);
  if (ans1 != Number.MAX_SAFE_INTEGER) {
    ans1 += 1;
  }
 
  // If B is reduced to B/2
  let ans2 = getMinOperations(A, Math.floor(B / 2), A, B, dp);
  if (ans2 != Number.MAX_SAFE_INTEGER) {
    ans2 += 1;
  }
 
  // If both A and B is reduced to sqrt(A * B)
  let ans3 = getMinOperations(
    Math.floor(Math.sqrt(A * B)),
    Math.floor(Math.sqrt(A * B)),
    A,
    B,
    dp
  );
  if (ans3 != Number.MAX_SAFE_INTEGER) {
    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
 
let A = 53,
  B = 16;
let mx = Math.max(A, B);
let dp = new Array(mx + 1).fill(0).map(() => new Array(mx + 1).fill(-1));
 
document.write(getMinOperations(A, B, -1, -1, dp));
 
// This code is contributed by saurabh_jaiswal.
</script>


Output

7

Time Complexity: O(max(A, B)^2)
Auxiliary Space: O(max(A, B)^2)

Efficient approach : Using DP Tabulation method ( Iterative approach )

The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Steps to solve this problem :

  • Create a 2D DP to store the solution of the subproblems and initialize it with 0.
  • Initialize the DP  with base cases
  • Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
  • Create three variables ans1, ans2, and ans3 to keep track of answers in 3 different conditions. 
  • update the current value of DP minimum of ans1, ans2 and ans3. 
  • At last return final answer stored in dp[A][B].

Implementation :

C++




// C++ program for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to return the minimum cost
// of converting A and B to 0
int getMinOperations(int A, int B) {
    int mx = max(A, B);
       
      // Initialize dp to store
    // computations of subproblems
    vector<vector<int>> dp(mx + 1, vector<int>(mx + 1, 0));
   
      // iterate over Dp to get the current value
      // from previous computation stored in DP
    for (int i = 1; i <= A; i++) {
        for (int j = 1; j <= B; j++) {
            if (i == 1 && j == 1) {
                dp[i][j] = 0;
            } else {
                  // intialize three answers variables
                int ans1 = INT_MAX, ans2 = INT_MAX, ans3 = INT_MAX;
                if (i >= 2) {
                    ans1 = dp[i/2][j];
                    if (ans1 != INT_MAX) {
                        ans1 += 1;
                    }
                }
                if (j >= 2) {
                    ans2 = dp[i][j/2];
                    if (ans2 != INT_MAX) {
                        ans2 += 1;
                    }
                }
                int s = sqrt(i*j);
                if (s*s == i*j) {
                    ans3 = dp[s][s];
                    if (ans3 != INT_MAX) {
                        ans3 += 2;
                    }
                }   
               
                  // update DP
                dp[i][j] = min({ ans1, ans2, ans3 });
            }
        }
    }
   
      // return answer
    return dp[A][B];
}
 
// Driver Code
int main() {
    int A = 53, B = 16;
      // function call
    cout << getMinOperations(A, B);
    return 0;
}
 
// this code is contributed by bhardwajji


Java




import java.util.*;
 
public class Main
{
 
  // Function to return the minimum cost
  // of converting A and B to 0
  static int getMinOperations(int A, int B) {
    int mx = Math.max(A, B);
 
    // Initialize dp to store
    // computations of subproblems
    int[][] dp = new int[mx + 1][mx + 1];
    for (int i = 1; i <= mx; i++) {
      Arrays.fill(dp[i], 0);
    }
 
    // iterate over Dp to get the current value
    // from previous computation stored in DP
    for (int i = 1; i <= A; i++) {
      for (int j = 1; j <= B; j++) {
        if (i == 1 && j == 1) {
          dp[i][j] = 0;
        } else {
           
          // intialize three answers variables
          int ans1 = Integer.MAX_VALUE, ans2 = Integer.MAX_VALUE, ans3 = Integer.MAX_VALUE;
          if (i >= 2) {
            ans1 = dp[i/2][j];
            if (ans1 != Integer.MAX_VALUE) {
              ans1 += 1;
            }
          }
          if (j >= 2) {
            ans2 = dp[i][j/2];
            if (ans2 != Integer.MAX_VALUE) {
              ans2 += 1;
            }
          }
          int s = (int)Math.sqrt(i*j);
          if (s*s == i*j) {
            ans3 = dp[s][s];
            if (ans3 != Integer.MAX_VALUE) {
              ans3 += 2;
            }
          }   
 
          // update DP
          dp[i][j] = Math.min(Math.min(ans1, ans2), ans3);
        }
      }
    }
 
    // return answer
    return dp[A][B];
  }
 
  // Driver Code
  public static void main(String[] args) {
    int A = 53, B = 16;
 
    // function call
    System.out.println(getMinOperations(A, B));
  }
}


Python3




import math
 
# Function to return the minimum cost
# of converting A and B to 0
def getMinOperations(A, B):
    mx = max(A, B)
     
    # Initialize dp to store
    # computations of subproblems
    dp = [[0 for j in range(mx+1)] for i in range(mx+1)]
   
    # iterate over Dp to get the current value
    # from previous computation stored in DP
    for i in range(1, A+1):
        for j in range(1, B+1):
            if (i == 1 and j == 1):
                dp[i][j] = 0
            else:
                # intialize three answers variables
                ans1, ans2, ans3 = math.inf, math.inf, math.inf
                if (i >= 2):
                    ans1 = dp[i//2][j]
                    if (ans1 != math.inf):
                        ans1 += 1
                if (j >= 2):
                    ans2 = dp[i][j//2]
                    if (ans2 != math.inf):
                        ans2 += 1
                s = int(math.sqrt(i*j))
                if (s*s == i*j):
                    ans3 = dp[s][s]
                    if (ans3 != math.inf):
                        ans3 += 2
               
                # update DP
                dp[i][j] = min(ans1, ans2, ans3)
           
    # return answer
    return dp[A][B]
 
# Driver Code
if __name__ == '__main__':
    A = 53
    B = 16
    # function call
    print(getMinOperations(A, B))


C#




using System;
 
public class GFG {
 
    // Function to return the minimum cost
    // of converting A and B to 0
    static int getMinOperations(int A, int B)
    {
        int mx = Math.Max(A, B);
 
        // Initialize dp to store
        // computations of subproblems
        int[, ] dp = new int[mx + 1, mx + 1];
 
        // iterate over Dp to get the current value
        // from previous computation stored in DP
        for (int i = 1; i <= A; i++) {
            for (int j = 1; j <= B; j++) {
                if (i == 1 && j == 1) {
                    dp[i, j] = 0;
                }
                else {
                    // intialize three answers variables
                    int ans1 = int.MaxValue,
                        ans2 = int.MaxValue,
                        ans3 = int.MaxValue;
                    if (i >= 2) {
                        ans1 = dp[i / 2, j];
                        if (ans1 != int.MaxValue) {
                            ans1 += 1;
                        }
                    }
                    if (j >= 2) {
                        ans2 = dp[i, j / 2];
                        if (ans2 != int.MaxValue) {
                            ans2 += 1;
                        }
                    }
                    int s = (int)Math.Sqrt(i * j);
                    if (s * s == i * j) {
                        ans3 = dp[s, s];
                        if (ans3 != int.MaxValue) {
                            ans3 += 2;
                        }
                    }
 
                    // update DP
                    dp[i, j] = Math.Min(
                        ans1, Math.Min(ans2, ans3));
                }
            }
        }
 
        // return answer
        return dp[A, B];
    }
 
    // Driver Code
    public static void Main()
    {
        int A = 53;
        int B = 16;
        // function call
        Console.WriteLine(getMinOperations(A, B));
    }
}


Javascript




// javascript program for the above approach
 
// Function to return the minimum cost
// of converting A and B to 0
function getMinOperations(A, B) {
    let mx = Math.max(A, B);
 
    // Initialize dp to store
    // computations of subproblems
    let dp = new Array(mx + 1);
    for (let i = 0; i <= mx; i++) {
        dp[i] = new Array(mx + 1).fill(0);
    }
 
    // iterate over Dp to get the current value
    // from previous computation stored in DP
    for (let i = 1; i <= A; i++) {
 
        for (let j = 1; j <= B; j++) {
 
            if (i === 1 && j === 1) {
                dp[i][j] = 0;
            }
 
            else {
 
                // intialize three answers variables
                let ans1 = Infinity, ans2 = Infinity, ans3 = Infinity;
                 
                if (i >= 2) {
                     
                    ans1 = dp[Math.floor(i / 2)][j];
                     
                    if (ans1 !== Infinity) {
                        ans1 += 1;
                    }
                }
 
                if (j >= 2) {
                     
                    ans2 = dp[i][Math.floor(j / 2)];
                     
                    if (ans2 !== Infinity) {
                        ans2 += 1;
                    }
                }
 
                let s = Math.floor(Math.sqrt(i * j));
                 
                if (s * s === i * j) {
                    ans3 = dp[s][s];
                    if (ans3 !== Infinity) {
                        ans3 += 2;
                    }
                }
 
                // update DP
                dp[i][j] = Math.min(ans1, ans2, ans3);
            }
        }
    }
 
    // return answer
    return dp[A][B];
}
 
// Driver Code
 
     
    let A = 53, B = 16;
     
    // function call
    console.log(getMinOperations(A, B));


Output

7

Time Complexity: O(max(A, B)^2)
Auxiliary Space: O(max(A, B)^2)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads