Given a positive integer ‘n’. Starting with 1 find the minimum cost required to convert it to n using the following operations :
- Multiply the number by 2 with costs a
- Add 1 to the number with costs b
- Subtract 1 from the number with costs c.
Examples:
Input: n = 31, a = 2, b = 5, c = 3 Output: 13 Explanation: The minimum cost transition to convert 1 to 31 is shown below:
- 1 -> 2 -> 4 -> 8 -> 16 -> 32 -> 31.
- Total cost = a+a+a+a+a+c = 2+2+2+2+2+3 = 13
Input: n = 31, a = 2, b = 1, c = 3 Output: 11 Explanation: The minimum cost transition to convert 1 to 31 is shown below:
- 1 -> 2 -> 3 -> 6 -> 7 -> 14 -> 15 -> 30 -> 31.
- Total cost = b+b+a+b+a+b+a+b = 1+1+2+1+2+1+2+1 = 11
Approach: To solve the problem follow the below idea:
The problem can be solved by exploring different paths to reach the target number while keeping track of the costs. This can be done using data structures such as priority queues. It starts with the number 1 and systematically applies three operations: Doubling the number, adding 1, and subtracting 1. These operations generate new numbers. The priority queue ensures that paths with lower costs are explored first, helping to find the minimum cost to reach the target number ‘n’. This approach is like searching the “cheapest” path through a number space to reach the desired value.
Let’s break down the approach and the code:
- A priority queue (min-heap) named ‘pq’ is used to store pairs of integers {number, cost}. The comparator for the priority queue ensures that pairs with lower costs come first. The code initializes ans (the minimum cost) to 0 and creates a vector vis of size 2 * n to mark visited numbers. The priority queue is initialized with the starting number 1 and cost 0.
- The loop continues until the priority queue is empty:
- The top element f of the priority queue is popped.
- If the popped number f.first is equal to the target number n, the minimum cost ans is updated to f.second, and the loop is exited.
- If the number f.first has already been visited, the loop continues without processing it again.
- If the number f.first * 2 is within the acceptable range and has not been visited, it’s pushed into the priority queue with an increased cost f.second + a.
- If the number f.first + 1 is within the acceptable range and has not been visited, it’s pushed into the priority queue with an increased cost f.second + b.
- If the number f.first – 1 is greater than 1 and has not been visited, it’s pushed into the priority queue with an increased cost f.second + c.
- After the loop ends, the minimum cost required to reach the target number n is stored in the variable ans, which is then printed.
- This approach is a variation of Dijkstra’s algorithm, where you explore possible number transitions with their associated costs. By using a priority queue, the algorithm always explores the path with the lowest cost first. This ensures that when the target number n is reached, the associated cost is indeed the minimum cost required to reach it.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
class X {
public :
bool operator()(pair< int , int >& a, pair< int , int >& b)
{
return a.second > b.second;
}
};
int min_cost( int n, int a, int b, int c)
{
int ans;
vector< int > vis(2 * n);
priority_queue<pair< int , int >, vector<pair< int , int > >,
X>
pq;
pq.push({ 1, 0 });
while (!pq.empty()) {
auto f = pq.top();
pq.pop();
if (f.first == n) {
ans = f.second;
break ;
}
if (vis[f.first] == 1)
continue ;
vis[f.first] = 1;
if (2 * f.first < 2 * n && vis[f.first * 2] == 0) {
pq.push({ f.first * 2, f.second + a });
}
if (f.first + 1 < 2 * n && vis[f.first + 1] == 0) {
pq.push({ f.first + 1, f.second + b });
}
if (f.first - 1 > 1 && vis[f.first - 1] == 0) {
pq.push({ f.first - 1, f.second + c });
}
}
return ans;
}
signed main()
{
ios_base::sync_with_stdio( false );
cin.tie(0);
cout.tie(0);
int n = 31;
int a = 2;
int b = 1;
int c = 3;
cout << min_cost(n, a, b, c) << "\n";
return 0;
}
|
Java
import java.util.*;
class Pair {
public int first, second;
Pair( int first, int second)
{
this .first = first;
this .second = second;
}
}
class X implements Comparator<Pair> {
public int compare(Pair a, Pair b)
{
return a.second - b.second;
}
}
public class GFG {
static int minCost( int n, int a, int b, int c)
{
int ans = 0 ;
boolean [] vis = new boolean [ 2 * n];
PriorityQueue<Pair> pq
= new PriorityQueue<>( new X());
pq.add( new Pair( 1 , 0 ));
while (!pq.isEmpty()) {
Pair f = pq.poll();
if (f.first == n) {
ans = f.second;
break ;
}
if (vis[f.first] == true )
continue ;
vis[f.first] = true ;
if ( 2 * f.first < 2 * n
&& vis[ 2 * f.first] == false ) {
pq.add( new Pair( 2 * f.first, f.second + a));
}
if (f.first + 1 < 2 * n
&& vis[f.first + 1 ] == false ) {
pq.add( new Pair(f.first + 1 , f.second + b));
}
if (f.first - 1 > 1
&& vis[f.first - 1 ] == false ) {
pq.add( new Pair(f.first - 1 , f.second + c));
}
}
return ans;
}
public static void main(String[] args)
{
int n = 31 ;
int a = 2 ;
int b = 1 ;
int c = 3 ;
System.out.println(minCost(n, a, b, c));
}
}
|
Python3
import heapq
def min_cost(n, a, b, c):
ans = 0
vis = [ 0 ] * ( 2 * n)
pq = []
heapq.heappush(pq, ( 0 , 1 ))
while pq:
cost, f = heapq.heappop(pq)
if f = = n:
ans = cost
break
if vis[f] = = 1 :
continue
vis[f] = 1
if 2 * f < 2 * n and vis[ 2 * f] = = 0 :
heapq.heappush(pq, (cost + a, 2 * f))
if f + 1 < 2 * n and vis[f + 1 ] = = 0 :
heapq.heappush(pq, (cost + b, f + 1 ))
if f - 1 > 1 and vis[f - 1 ] = = 0 :
heapq.heappush(pq, (cost + c, f - 1 ))
return ans
n = 31
a = 2
b = 1
c = 3
print (min_cost(n, a, b, c))
|
C#
using System;
using System.Collections.Generic;
class X : IComparer<Pair> {
public int Compare(Pair a, Pair b) {
return a.Second.CompareTo(b.Second);
}
}
class Pair {
public int First { get ; set ; }
public int Second { get ; set ; }
public Pair( int first, int second) {
First = first;
Second = second;
}
}
class GFG {
static int MinCost( int n, int a, int b, int c) {
int ans = 0;
bool [] vis = new bool [2 * n];
PriorityQueue<Pair> pq = new PriorityQueue<Pair>( new X());
pq.Enqueue( new Pair(1, 0));
while (pq.Count > 0) {
Pair f = pq.Dequeue();
if (f.First == n) {
ans = f.Second;
break ;
}
if (vis[f.First] == true ) continue ;
vis[f.First] = true ;
if (2 * f.First < 2 * n && vis[2 * f.First] == false ) {
pq.Enqueue( new Pair(2 * f.First, f.Second + a));
}
if (f.First + 1 < 2 * n && vis[f.First + 1] == false ) {
pq.Enqueue( new Pair(f.First + 1, f.Second + b));
}
if (f.First - 1 > 1 && vis[f.First - 1] == false ) {
pq.Enqueue( new Pair(f.First - 1, f.Second + c));
}
}
return ans;
}
public static void Main( string [] args) {
int n = 31;
int a = 2;
int b = 1;
int c = 3;
Console.WriteLine(MinCost(n, a, b, c));
}
public class PriorityQueue<T> {
private List<T> data;
private IComparer<T> comparer;
public PriorityQueue(IComparer<T> comparer) {
this .data = new List<T>();
this .comparer = comparer;
}
public void Enqueue(T item) {
data.Add(item);
int ci = data.Count - 1;
while (ci > 0) {
int pi = (ci - 1) / 2;
if (comparer.Compare(data[ci], data[pi]) >= 0)
break ;
T tmp = data[ci]; data[ci] = data[pi]; data[pi] = tmp;
ci = pi;
}
}
public T Dequeue() {
int li = data.Count - 1;
T frontItem = data[0];
data[0] = data[li];
data.RemoveAt(li);
--li;
int pi = 0;
while ( true ) {
int ci = pi * 2 + 1;
if (ci > li) break ;
int rc = ci + 1;
if (rc <= li && comparer.Compare(data[rc], data[ci]) < 0)
ci = rc;
if (comparer.Compare(data[pi], data[ci]) <= 0) break ;
T tmp = data[pi]; data[pi] = data[ci]; data[ci] = tmp;
pi = ci;
}
return frontItem;
}
public T Peek() {
T frontItem = data[0];
return frontItem;
}
public int Count => data.Count;
}
}
|
Javascript
class Pair {
constructor(first, second) {
this .first = first;
this .second = second;
}
}
class PriorityQueue {
constructor() {
this .queue = [];
}
add(pair) {
this .queue.push(pair);
this .queue.sort((a, b) => a.second - b.second);
}
poll() {
if ( this .isEmpty()) {
return null ;
}
return this .queue.shift();
}
isEmpty() {
return this .queue.length === 0;
}
}
function minCost(n, a, b, c) {
let ans = 0;
const vis = new Array(2 * n).fill( false );
const pq = new PriorityQueue();
pq.add( new Pair(1, 0));
while (!pq.isEmpty()) {
const f = pq.poll();
if (f.first === n) {
ans = f.second;
break ;
}
if (vis[f.first]) {
continue ;
}
vis[f.first] = true ;
if (2 * f.first < 2 * n && !vis[2 * f.first]) {
pq.add( new Pair(2 * f.first, f.second + a));
}
if (f.first + 1 < 2 * n && !vis[f.first + 1]) {
pq.add( new Pair(f.first + 1, f.second + b));
}
if (f.first - 1 > 1 && !vis[f.first - 1]) {
pq.add( new Pair(f.first - 1, f.second + c));
}
}
return ans;
}
const n = 31;
const a = 2;
const b = 1;
const c = 3;
console.log(minCost(n, a, b, c));
|
Time Complexity: O(n * log(n)) Auxiliary Space: O(n)
|