📅  最后修改于: 2023-12-03 15:27:17.766000             🧑  作者: Mango
给定一个由非负整数组成的矩阵,我们要找到一条路径,使得路径上的每个元素都来自矩阵的唯一行和列,且路径上元素的和尽可能大。
给定一个 $m\times n$ 的矩阵 $M$,任意两个元素都不相同。
我们要求找到矩阵 $M$ 中的一个路径 $p$,满足:
路径 $p$ 由一个起点和一个终点组成。
路径 $p$ 的每一个元素都是矩阵 $M$ 中的某一行或某一列中的元素。
路径 $p$ 中的每个元素都来自于不同的行或列。
路径 $p$ 上元素的总和最大。
请编写一个函数来计算矩阵的最大总和,并返回该路径。
输入:
[
[5, 7, 2, 8],
[3, 0, 9, 4],
[6, 6, 2, 8]
]
输出:[3, 1, 0, 2, 3]
我们可以将这个问题模型化成最大权匹配问题。
一个行与列相互匹配,意味着这个路径经过矩阵中的一对位置。假设我们可以给每个行和列赋予一个权重,那么我们的任务就是去找到一些一对一的匹配,满足所有的匹配的权重和最大。对于一个可能的匹配,其权重等于行权重与列权重之和。
注意到此问题是二分图最大权匹配问题,可以用匈牙利算法来解决。
具体地,在执行匈牙利算法时,在邻接矩阵的每个位置建立一个点。
每个行点 $i$ 连向其所在行的位置,每个列点 $j$ 连向其所在列的位置。若位置 $(i, j)$ 上的值为 $w_{i, j}$,则从行点 $i$ 到列点 $j$ 连接一条权值为 $w_{i, j}$ 的边。
最后得到的匹配中,行点 $i$ 与列点 $match[i]$ 所在的列之间是匹配的。注意到如果匹配不全,我们需要较少列点的数量以匹配行点。
假设矩阵 $M$ 的维度是 $m\times n$。
建立邻接矩阵需要 $O(mn)$,匈牙利算法的时间复杂度为 $O(m^2n)$。因此总时间复杂度为 $O(m^2n)$。
建立邻接矩阵需要 $O(mn)$ 的空间,匈牙利算法的空间复杂度为 $O(m+n)$。因此总空间复杂度为 $O(mn)$。
from typing import List
class Solution:
def maxSumOfMatrix(self, matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
row_weights = [max(row) for row in matrix]
col_weights = [0] * n
# 建立邻接矩阵
adj = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
adj[i][j] = row_weights[i] + col_weights[j] - matrix[i][j]
# 匈牙利算法
match = [-1] * m
vis1, vis2 = [False] * m, [False] * n
def dfs(u: int) -> bool:
vis1[u] = True
for v in range(n):
if not vis2[v] and adj[u][v] == 0:
vis2[v] = True
if match[v] == -1 or dfs(match[v]):
match[v] = u
return True
return False
for i in range(m):
vis1 = [False] * m
dfs(i)
return [match[i], i, i, match[i+1], i+1 for i in range(0, len(match), 2)]