I have a problem where I have n number of towers with i bricks. I need to rearrange them in descending order. I can only move on brick at a time to an adjacent tower. For example, for this problem:
4 3 0 1 1
The answer is 1 move as I can move one brick from the second tower to the third tower and have: 4 2 1 1 1.
For a problem like:
7 0 0 0 1
The answer is 3 moves to get: 7 1 0 0 0 or 6 1 1 0 0.
I currently have this function:
def compute_min_moves(towers, moves = 0):
# Si 0 o 1 torre, no se hace nada
if len(towers) < 2:
return moves
for i in range(len(towers)-1, 0 ,-1):
if towers[i - 1] < towers[i]:
diff = 0
while towers[i - 1] < towers[i]:
diff += 1
towers[i - 1] += diff
towers[i] -= diff
moves += diff
sub_array = towers[i-1:]
if not all(earlier >= later for earlier, later in zip(sub_array, sub_array[1:])):
moves = compute_min_moves(towers, moves)
return moves
I don't see how we could get the optimal solution.
Your initial solution only ever moved bricks between towers right to left, so the solution you proposed to 4 3 0 1 1, which is an optimal one, couldn't ever be found (since it moves pieces from left to right).
You made some adjustments to the algorithm that narrow the problem, but still only moves bricks left to right, and it loses track of what has been done before.
Another issue with the algorithm you came up with is that it keeps moving bricks from a tower until it has been equalised with the one next to it, which isn't necessarily the fastest way to a solution.
Here's an approach that works more generally: since you require the smallest number of moves, a breadth-first search is the best way to go. By exploring all possible moves from the starting position, and then all possible moves from those n=1 positions, and so on, you can guarantee that the first time you reach a solution, you will have done so in the fewest number of moves (although it won't find all such solutions - it terminates after finding a first).
What further complicates the problem, is that moves in both directions are allowed, you need to ensure you don't create cycles in the search.
A good mechanism for a breadth-first search is to create a queue of positions explored so far, adding newly reachable positions to the end of the queue (if they don't outright solve the problem) and continuing to do so while reading from the start of the queue.
Also note that it's clear that a solution can always be reached and that an algorithm like this will terminate if it succeeds in avoiding cycles. Eventually, all possible positions would be reached, and at least one of those will be sorted from high to low, left to right (many will, but we only need to believe it will always reach at least one).
Here's an example implementation of that approach.
Output:
I did not see a straightforward way from the solution you had so far to one that always finds the optimal solution, so I opted to share a solution that I came up with. Please do investigate your own solution more closely based on the feedback above, and don't simply accept 'the answer' - I assume this is part of an assignment that's supposed to teach you something, so it won't help if you submit my work as your own. Perhaps only look at it and then try to implement your own based on what you learned.
A nice addition to explore the process:
And define
queueas:Output: