Home > database >  Algorithm to find minimum number of moves to transform one number to another
Algorithm to find minimum number of moves to transform one number to another

Time:01-30

Suppose we are given two positive integers, a and b. Each move we are allowed to divide a by 2 (but only if a is even), multiply a by 2, or add 1 to a. How many moves does it take to change a to b? Find either a direct formula or an efficient algorithm (i.e. one that runs in logarithmic time).

Some progress that I have made: We can think of it as writing b=(2^k)a something, where this "something" can be expressed by the sum of powers of 2 (including negative exponents). Clearly we'd want to choose k so that k is a large as possible while maintaining (2^k)a<b, and we'd want k to be the total difference between the ×2s and the ÷2s. However I'm not too sure how to go from here. Does someone have solution?

CodePudding user response:

One approach I can think of is to maintain a tree, with the root node as the initial number. Every node has three children, each of which resembles one operation (double, half, increment), unless of course the number is odd, in which case the half operation won't be counted. You can do a simple BFS in order to find the first instance in which the target value is seen. Here is some sample code in C (p1 is the initial value, p2 is the target):

unordered_set<uint64_t> set; // Resembles the previous layer
unordered_set<uint64_t> visited; // Visited set. If we already came across a node, then there isn't any point in evaluating it again
set.insert(p1); // First layer contains the initial value
visited.insert(p1);
int count = 0;

while (!set.count(p2)) { // Loop until you reach the target value
    unordered_set<uint64_t> new_set; // Build the new layer

    for (uint64_t elem : set) {
        if ((elem & 1) == 0) { // Divide by two if it's even (>> 1 is the same as divide by 2)
            if (!visited.count(elem >> 1)) {
                new_set.insert(elem >> 1);
                visited.insert(elem >> 1);
            }
        }

        if (!visited.count(elem   1)) {
            new_set.insert(elem   1);
            visited.insert(elem   1);
        }
                
        if (!visited.count(elem << 1) && elem < p2) {
            new_set.insert(elem << 1);
            visited.insert(elem << 1);
        }
    }

    set = new_set; // Update current layer
    count  ;
}

cout << count << endl;

CodePudding user response:

Here's my take, done in C#.

var a = 2;
var b = 15;

var found = new HashSet<int>() { a };

int Remember(int value)
{
    found.Add(value);
    return value;
}

var operations = new[]
{
    new { operation = "/2", condition = (Func<int, bool>)(x => x % 2 == 0), projection = (Func<int, int>)(x => x / 2) },
    new { operation = "*2", condition = (Func<int, bool>)(x => x <= int.MaxValue / 2), projection = (Func<int, int>)(x => x * 2) },
    new { operation = " 1", condition = (Func<int, bool>)(x => true), projection = (Func<int, int>)(x => x   1) },
};

var candidates = new[] { new { count = 0, operations = $"{a}", value = a } };

while (!found.Contains(b))
{
    candidates =
    (
        from c in candidates
        from x in operations
        where x.condition(c.value)
        let test = x.projection(c.value)
        where !found.Contains(test)
        let value = Remember(test)
        select new
        {
            count = c.count  1,
            operations = $"{c.operations}, {x.operation}",
            value,
        }
    ).ToArray();
}

var result = candidates.Where(x => x.value == b).First();

Console.WriteLine($"{result.count} operations: {result.operations} = {result.value}");

That outputs:

5 operations: 2,  1, *2,  1, *2,  1 = 15

Basically, this is starting with a at the zeroth step. It then takes this generation and produces all possible values from the operations to create the next generation. If it produces a value that it has already seen it discards the value as there is an equal or faster operation to produce the value. It keeps repeating until b is found.

  •  Tags:  
  • Related