So imagine you are given a m * n matrix like this:
Grid = 4 * 4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
You want to connect from the top left corner to the bottom right corner and you can only go right or down. In addition, you want to find the operations needed to get the desired sum.
For example:
def move(m, n, sum):
count = m + n - 1
max_val = m
s = sum
r = []
while max_val > 0:
if count <= 0:
return False, r
least = max_val * ((max_val - 1) / 2)
r.append(max_val)
s -= max_val
count -= 1
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
r.append(max_val)
s -= max_val
count -= 1
if s < least:
return False, r
max_val -= 1
return True, r
def combine(m, n, sum):
result, new_res = move(m, n, sum)
new_res.reverse()
for i in range(1, len(new_res)):
if new_res[i] == new_res[i - 1]:
print("R")
else:
print("D")
combine(4, 4, 16)
I don't quite understand the solution.
Can someone explain the Algorithm?
Especially in the function move where it does this check in the while loop:
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
Thank you!
So the script isn't well written nor follow best practices, having say that I re adjust it and hopefully is more clear
NOTE: I've added to my GitHub Algorithm-Complete-Guide which is under construction, feel free to use it
def move(m, n, weight_limit):
# ==== < CONFIG VARIABLES > ==== #
step_counter = m + n - 1
max_val = m # NOTE: It starts from the last Value (4) and Goes Backwards
path = [] # NOTE: Stores the path (need to reverse it afterwards)
while max_val:
if step_counter <= 0: # NOTE: starting Node so it break Not need to return
break
least = max_val * ((max_val - 1) / 2)
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
if weight_limit < least: # NOTE: Moved it up here because makes more sense to check this first and break
break
# ==== < ROW CHECK | CAN IT GO TO THE LEFT? > ==== #
if step_counter: # NOTE: Moved it as makes it more clear
check_row = least + (step_counter - (max_val - 1)) * (max_val - 1)
while weight_limit > check_row: # FAQ: 1 Footnotes
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
max_val -= 1
return path
def combine(m, n, sum):
path = move(m, n, sum)
path.reverse() # NOTE: Reverse the result Path
result = []
for i in range(1, len(path)):
if path[i] == path[i - 1]: # NOTE: Check if next Value is the same then it moved it to the Right
result.append((path[i], 'Right'))
else:
result.append((path[i], 'Left'))
return result
def prettify_result(res):
for value in res:
print(f'V={value[0]}) {value[1]} |-> ', end='')
if __name__ == '__main__':
path = combine(4, 4, 16)
prettify_result(path)
I first thought was a Rat in a Maze problem solved with Backtracking technique of the Algorithm Depth-first_search that runs at Time Complexity: O(2^(n^2)) but after a review I doubt it, and it seems more a kind of Dijkstra's algorithm but I may be wrong. I don't think is Backtracking simple because is not recursive (and never backtracks..) but because it checks for the Node's Weight it seem a Dijkstra's with a given Max-Weight.
Important note, the Maze is solved Upside down, from bottom to top! So It starts at Value 4 and runs backwards! Hence in reality is checking:
"function move, what is least + (count - (max_val - 1)) * (max_val - 1)" this I had some hard time to understand as well, basically is just a Math trick and I added it in a variable called check_row
to make it more explicit, but basically what it does it check if can go to the Left or not.
At the end of the Algorithm it reverse the list backwards, so that looks like it went from Top to Bottom.
The function move()
returns always 2 value, first of which if False
and stores is in variable result
but is not even used. It is pretty weird (seems not got programming practice) and not used anyway so I just removed and replace it with a break
statements. That's because makes more sense to break in a while loop rather than return. The Function then takes care to return path
at the end.
I remove many while max_val > 0
or similar bool
checks against the 0 because is completely redundant and not Pythonic, as Guide realpython.com/python-conditional-statements/
BACKTRACKING
Depth-first search
Dijkstra's algorithm