我用我自己的 Lisp 方言实现了它,所以源代码对你没有太大帮助 :-) ...
编辑:也添加了 Python 版本。
不管怎样,这个想法是:
- 编写一个函数
paths(i, j) --> (maxlen, number),它返回从(i, j) 开始的最大路径长度以及存在的路径数量..
- 此函数是递归的,查看
(i, j) 的值为 M[i][j]+1 的邻居将调用 paths(ni, nj) 以获取有效邻居的结果
- 如果邻居的最大长度大于当前最大长度,则设置新的当前最大长度并重置计数器
- 如果最大长度与当前长度相同,则将计数器添加到总长度中
- 如果最大长度较小,则忽略该邻居结果
- 缓存单元的计算结果(这非常重要!)。在我的版本中,代码分为两个相互递归的函数:
paths首先检查缓存,否则调用compute-paths; compute-paths 在处理邻居时调用 paths。递归调用的缓存大致相当于显式动态编程方法,但有时更容易实现。
要计算最终结果,您基本上执行相同的计算,但将所有0 单元格的结果相加,而不是考虑邻居。
请注意,不同路径的数量可能会变得很大,这就是为什么枚举所有路径不是一个可行的选择,并且缓存/DP 是必须的:例如,对于值为 M[i][j] = i+j 的 N=20 矩阵,有 35,345,263,800最大路径长度为 38。
这个算法在时间上是 O(N^2) (每个单元最多被访问一次)并且需要 O(N^2) 空间用于缓存和递归。当然,鉴于输入由 N^2 个数字本身组成,并且您至少需要阅读它们来计算答案,因此您不能期望得到比这更好的结果。
(defun good-paths (matrix)
(let** ((N (length matrix))
(cache (make-array (list N N)))
(#'compute-paths (i j)
(let ((res (list 0 1))
(count (1+ (aref matrix i j))))
(dolist ((ii jj) (list (list (1+ i) j) (list (1- i) j)
(list i (1+ j)) (list i (1- j))))
(when (and (< -1 ii N) (< -1 jj N)
(= (aref matrix ii jj) count))
(let (((maxlen num) (paths ii jj)))
(incf maxlen)
(cond
((< (first res) maxlen)
(setf res (list maxlen num)))
((= (first res) maxlen)
(incf (second res) num))))))
res))
(#'paths (i j)
(first (or (aref cache i j)
(setf (aref cache i j)
(list (compute-paths i j))))))
(res (list 0 0)))
(dotimes (i N)
(dotimes (j N)
(when (= (aref matrix i j) 0)
(let (((maxlen num) (paths i j)))
(cond
((< (first res) maxlen)
(setf res (list maxlen num)))
((= (first res) maxlen)
(incf (second res) num)))))))
res))
编辑
以下是上述内容在 Python 中的音译,如果你之前没见过 Lisp,应该会更容易理解……
def good_paths(matrix):
N = len(matrix)
cache = [[None]*N for i in xrange(N)] # an NxN matrix of None
def compute_paths(i, j):
maxlen, num = 0, 1
count = 1 + matrix[i][j]
for (ii, jj) in ((i+1, j), (i-1, j), (i, j-1), (i, j+1)):
if 0 <= ii < N and 0 <= jj < N and matrix[ii][jj] == count:
nh_maxlen, nh_num = paths(ii, jj)
nh_maxlen += 1
if maxlen < nh_maxlen:
maxlen = nh_maxlen
num = nh_num
elif maxlen == nh_maxlen:
num += nh_num
return maxlen, num
def paths(i, j):
res = cache[i][j]
if res is None:
res = cache[i][j] = compute_paths(i, j)
return res
maxlen, num = 0, 0
for i in xrange(N):
for j in xrange(N):
if matrix[i][j] == 0:
c_maxlen, c_num = paths(i, j)
if maxlen < c_maxlen:
maxlen = c_maxlen
num = c_num
elif maxlen == c_maxlen:
num += c_num
return maxlen, num