BFS for arithmetic operations

后端 未结 3 1899
余生分开走
余生分开走 2021-01-24 08:35

Convert a number m to n with minimum operations. The operations allowed were subtraction by 1 and multiplication by 2.

For Eg : 4 and 6. Answer is 2. 1st operation : -1

相关标签:
3条回答
  • 2021-01-24 08:48

    BFS is not exactly an option here, due to the exponential growth (2 ^ (n - 1) to 2^n trys are performed, where n is the number of required steps). Instead try to find logic rules for generating the required number.

    Let a be the input-number and b the number that should be produced.

    There are three cases:

    • a == b, this case is trivial and just listed for completeness
    • a > b, the solution is a - b times substracting by -1
    • a < b: This is the more tricky part

    The smallest number of operations requires the minimum number of multiplications and substractions. Substractions can easily be minimized due to the following fact: (a - 1) * 2 = a * 2 - 2. Thus we can easily reduce the number of substractions by any number that is a power of 2 by simply substracting before multiplying.
    Since we can only substract and multiply, the minimum number of multiplications is min n => a * 2 ^ n >= b.
    Using this fact we can determine the amount to substract: s = b - 2 ^ n * a.

    The implementation would look like this in pseudocode (can't provide python code):

    //using the same variable-names as above in the description
    minOp(int a , int b)
        //find minimum number of multiplications
        int n
        for(n = 0 ; a << n < b ; n++)
            noop
    
        //find amount to substract
        int s = (a << n) - b
    
        for(int i = 0 ; i < n ; i++)
            print("(")
    
        print(a)
    
        //calculate operations
        while(n > 0)
            //calculate number of times we need to substract here (minimization of substractions)
            while(s >= 1 << n)
                print(" - 1")
                s -= 1 << n
    
            print(")")
    
            //divide by two
            print(" * 2")
            n -= 1
    
        while(s >= 1 << n)
            print(" - 1")
            s -= 1 << n
    
        print(" = ")
        print(b)
    

    This implementation aswell covers the cases a == b - with n = 0 and s = 0 - and a > b - with n = 0 and s = a - b.

    A test-run in a java-implementation of the above would produce this output:

    (((4) * 2 - 1) * 2 - 1) * 2 = 26

    The simplification of the above calculation shows the idea behind this algorithm:

    ((4 * 2 - 1) * 2 - 1) * 2 = 26
    (4 * 2 * 2 - 2 - 1) * 2 = 26
    4 * 2 * 2 * 2 - 3 * 2 = 26
    32 - 6 = 26
    

    Thanks to @user3386109 for this explanation:
    Assume that the start value is A, and the goal value is B. The first step is to create a list of target values starting at B, and proceeding by dividing by 2 (rounding up if necessary). For example, if B is 26, then the list of target values would be 26, 13, 7, 4, 2, 1. If the start value A is any of those target values, then you can easily climb to the goal B (by multiplying by 2 and subtracting 1 if necessary). If A is not one of those values, then you begin by subtracting 1 from A until you reach one of those target values. For example, if A is 6, then two subtractions are needed to reach 4, and then you climb from 4 to 26. If A is 12, five subtractions are needed to reach 7, and so on. Obviously, if A is larger than B, then all you do is subtract one until you reach B

    0 讨论(0)
  • 2021-01-24 08:55

    Your algorithm is exponential, at each additional "breadth level" you add 2 new values for each value in the previous level. For example:

    26                                                            (breadth = 0)
    25, 52                                                        (breadth = 1)
    24, 50, 51, 104                                               (breadth = 2)
    23, 48, 49, 100, 50 (skipped because seen), 102, 103, 208     (breadth = 3)
    22, 46, 47, 96, 48 (skip), 98, 99, 200                        (breadth = 4)
    21, 44, 45, 92, 46, 94, 95, 192, 97, 196, 199, 400            (breadth = 5)
    

    The solution for the case src=26, dst=5 is to subtract 1 until you reach 5, that takes 21 "breadth levels" = 21 operations. At that level both your queue and your seen_list will contain ~2^20 values; and for each value in the queue you do a linear search to see if it's present in the list, so that level will consist of 2^20 * 2^20 comparisons = 2^40 ~ 1 thousand billion comparisons. That takes time, and it's just the last level.

    You should think of a better algorithm. For starters, if your current value is higher than the target, there is no point in doubling it as it will surely only add additional steps.. This consideration alone will reduce the number of steps for this case from millions to 21 (you'll just subtract 1 until you reach the target value, and this will happen in general when src > dest)

    0 讨论(0)
  • 2021-01-24 08:56

    This code hopefully implements the above-mentioned very efficient algorithm.

    private static int solve(int n, int m) {
    
    int steps = 0;
    int cur = n;
    ArrayList<Integer> arr = new ArrayList<>();
    
    arr.add(m);
    for (int i = 0; !arr.contains(1); ++i)
        arr.add((int) Math.round((double) arr.get(i) / 2));
    
    while (cur != m) {
        if (arr.contains(cur))
            cur *= 2;
        else
            cur--;
    
        steps++;
       }
    
    return steps;
    }
    

    Explanation::

    Imagine a stair and starting from (n) you've got to reach its top (i.e: the number m), so you decided to make list of all the best steps to take, then you refer to the number you have and see if it exists in that list you made for an optimal solution, if it's there then you just follow the steps and you'll get the best solution, if not you'll have to align yourself to the optimal steps (say by subtracting 1) and then you're on the optimal track and vooooom to your destination. For more: please, refer to the explanation in mr.paul solution up there explains this better.

    0 讨论(0)
提交回复
热议问题