0

I'm given integers X, Y, and Z. In each step, I can either multiply or divide, by either 2 or 3. I need to transform X to Z in exactly Y steps ... or determine that it's not possible.

For Example:

X is 9,
Y is 8,
Z is 4.

9 can become 4 by: 9/3/3x2x2x2x2/2/2 = 4 As you can see I made 8 operations.

How can this be done in Python?

Prune
  • 76,765
  • 14
  • 60
  • 81
Diego Doe
  • 1
  • 1
  • 1
    @nevabyte How do you make 5 from 1 then? – Stefan Pochmann Apr 26 '17 at 21:17
  • @MosesKoledoye The divisors are not arbitrary, they are either 2 or 3 or both. – Diego Doe Apr 26 '17 at 21:22
  • @nevabyte Um, huh? But ok, ignore the 1 and make 5 using 2 and 3 then. – Stefan Pochmann Apr 26 '17 at 21:25
  • @nevabyte So? 1 isn't 5. Make **5**. – Stefan Pochmann Apr 26 '17 at 21:27
  • 1
    Um, what do you mean the "real" number for `2 / 3 * 3 ` is 1.99999999? – juanpa.arrivillaga Apr 26 '17 at 21:47
  • @nevabyte That long expression doesn't make 5 but 32768/6561. Try again? Btw, you did start from 1 after all, so why did you complain about that earlier? – Stefan Pochmann Apr 26 '17 at 21:55
  • 1
    @nevabyte Again, what do you mean **the real number?**. `2/3*3` is *exactly equal* to 2. Which happens to be *exactly equal* to `1.99999....` So again, what are you trying to get at? – juanpa.arrivillaga Apr 26 '17 at 21:59
  • @nevabyte Well show us how then. – Stefan Pochmann Apr 26 '17 at 22:02
  • @nevabyte I see what you are getting at now. Not sure of the validity, it's been a while since I did any analysis, but I know what you mean now. – juanpa.arrivillaga Apr 26 '17 at 22:19
  • @juanpa.arrivillaga I don't think nevabyte's idea works. If we apply logarithms, the problem becomes turning log(1)=0 into log(5) by adding ±log(2) and ±log(3). So now we're talking about a series like nevabyte did. Is that how you understood it as well? The problem is, there is no series with those terms that converges to log(5), or even converges at all. Because we're always jumping up or down by at least log(2). While we might **get** arbitrarily close to the goal, we can't **stay** close enough. – Stefan Pochmann May 01 '17 at 09:43
  • Same with multiplication (i.e., no log). We might **get** arbitrarily close to 5 with some prefix product, but the very next prefix product will be far away again, as we have to multiply or divide by at least 2. So we don't **stay** close enough to "converge" to 5. – Stefan Pochmann May 01 '17 at 09:43

2 Answers2

1

First of all use descriptive variable names, such as start, target, and steps.

No, there isn't an easy way to do this, but there are straightforward ways.

First, you need to find the necessary change. Break down both start and target into factors of 2, factors of 3, and anything else. If this "anything" else" doesn't match, then you can't solve the problem at all.

For instance, look at your given problem: going from 9 to 4. Breaking down each number:

9 = 3*3    # no 2's, no other stuff
4 = 2*2    # no 3's, no other stuff

Since the "other" stuff matches (i.e. 1), you can make the transition. You need to remove 2 factors of 3, and add 2 factors of 2. That's 4 steps. From there, all you have to do is add pairs of *3/3 or *2/2 until you have 8 steps.

Let's try with changing 56 into 126:

 56 = 2*2*2*7   # no 3's, other = 7
126 = 2*3*3*7   # other = 7

To make the transition, you need to remove two 2's and add two 3's. That's four steps; you adjust to the desired number as before.

There's your attack; can you code that?

Prune
  • 76,765
  • 14
  • 60
  • 81
  • But what if I have 9 operations total and by the time I get to the target I'm one division or one multiplicacion short? – Diego Doe Apr 26 '17 at 22:16
  • If you're short by an odd quantity of operations, you can't solve the problem as given. – Prune Apr 26 '17 at 22:48
  • Do you know the most efficient way to calculate the prime factors of a number? I try the: for x in range(2,number) and then asking if (number%x ==0) saving the numbers that enter the if in cuestion. – Diego Doe Apr 27 '17 at 03:41
  • I already have the code done thanks to your tip, is just that my program just snaps when I enter a number > 3^15 :( – Diego Doe Apr 27 '17 at 03:43
  • Most of all, note that you do *not* need a complete prime factorization: all you need is factors of 2 and 3. As for primes in general, there's no one best way, but there are myriad solutions in the research you supposedly did before you posted. Try "prime sieve". – Prune Apr 27 '17 at 16:01
  • Also, if you have a new problem with your code, please post another question. – Prune Apr 27 '17 at 16:01
0

Just for fun, here is a brute-force approach that scales horrifically -- O(y^4),

def bruteforce(x, y, z, acc="", accv=None):
    if accv == z and len(acc) == y*2:
        return acc
    if accv is None:
        accv = x
    if len(acc) == y*2:
        return
    m2 = bruteforce(x, y, z, acc+'*2', accv*2)
    m3 = bruteforce(x, y, z, acc+'*3', accv*3)
    d2 = bruteforce(x, y, z, acc+'/2', accv/2)
    d3 = bruteforce(x, y, z, acc+'/3', accv/3)
    return m2 or m3 or d2 or d3

In action:

In [49]: exp = bruteforce(9, 8, 4)

In [50]: exp
Out[50]: '*2*2*2*2/2/2/3/3'

In [51]: eval('9'+exp)
Out[51]: 4.0

In [52]: exp = bruteforce(13, 8, 4)

In [53]: exp

In [54]: exp = bruteforce(9, 7, 2)

In [55]: exp
Out[55]: '*2*2*2/2/2/3/3'

In [56]: eval('9'+exp)
Out[56]: 2.0

Will be buggy because of floating-point inaccuracy...

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172