It appears that what you're looking for are N minimum values where the row and column index for each value is unique (assuming an NxN matrix). If we tag each value in the matrix with it's initial coordinates, we can rearrange them without losing the ability to tell where they came from. I'm not sure there's a slick way to sort with a custom key in numpy, so here's a vanilla Python solution with no recursion or backtracking required:
def idx_matrix(matrix):
# return 1-D array of matrix values in (row_idx, col_idx, val) format
return [(r, c, val) for r, row in enumerate(matrix)
for c, val in enumerate(row)]
def find_minima(indexed_vals, limit=0):
# return array of indexed matrix values whose row and col indexes are unique
minima = []
rows = set()
cols = set()
for row, col, val in indexed_vals:
if row not in rows and col not in cols:
minima.append((row, col, val))
if limit and len(minima) == limit:
# optional optimization if you want to break off early
# after you've found a value for every row
break
rows.add(row)
cols.add(col)
return minima
def sort_by_val(indexed_vals):
# return indexed_vals sorted by original matrix value
return sorted(indexed_vals, key=lambda x: x[2])
def sort_by_row(indexed_vals):
# return indexed_vals sorted by row index
return sorted(indexed_vals, key=lambda x: x[0])
def strip_indices(indexed_vals):
# return a 1-D array with row and col index removed
return [v[2] for v in indexed_vals]
def find_minima_by_row(matrix):
# put it all together
indexed = idx_matrix(matrix)
indexed = sort_by_val(indexed)
minima = find_minima(indexed)
minima = sort_by_row(minima)
return strip_indices(minima)
matrix = [[4, 5, 6],
[1, 2, 3],
[7, 8, 9]]
results = find_minima_by_row(matrix)
print(f'{results=}')
matrix = [[20, 17, 5, 13, 19],
[11, 22, 8, 4, 9],
[ 0, 10, 2, 16, 23],
[ 1, 24, 21, 15, 14],
[ 3, 12, 6, 7, 18]]
results = find_minima_by_row(matrix)
print(f'{results=}')
results=[5, 1, 9]
results=[5, 4, 0, 14, 12]
This ran in ~4 seconds with a 2000x2000 matrix on my workstation. You could do the sorts in place to be a little more space efficient.
I also see no reason why this wouldn't work if there are repeated values in the input.
[4, 2, 9], or[6, 1, 8], or[5, 3, 7]?1in the first row, since1is the lowest value in the grid [...]"). But what about the input[[4, 5, 6],[1, 2, 3],[7, 101, 100]]? If you always pick the smallest number in the grid, you end up with the solution[5,1,100], but the answer[2,6,7]has a smaller sum.