给出一个像这样的简单无向图:
从D,A,B或C(V_start
)开始 - 我必须计算从起点(V_start
)到起点({{1})的可能路径数量} V_start
步骤,其中每个边和顶点可以无限次访问。
我正在考虑进行深度优先搜索,在n
时停止,但是,如果steps > n || (steps == n && vertex != V_start)
,这会变得相当昂贵。我的下一个想法让我将DFS与动态编程相结合,然而,这就是我被困住的地方。
(这不是家庭作业,只是为了学习而被困在图表和算法中。)
如何在合理的时间内使用大n = 1000000
来解决这个问题?
答案 0 :(得分:20)
此任务通过矩阵乘法求解。
如果存在从n
到n
的路径,则创建包含0和1的矩阵mat[i][j]
x i
(对于单元格j
为1)。将此矩阵乘以k
次(考虑使用快速矩阵求幂)。然后在矩阵的单元格mat[i][j]
中,您拥有从k
开始到i
结尾的长度为j
的路径数。
注意:快速矩阵取幂基本上与快速取幂相同,只是你将数乘以矩阵乘以数字。
注2:让我们假设n
是图中的顶点数。然后我在这里提出的算法在时间复杂度O(log k * n 3 )中运行,并且具有O(n 2 )的存储器复杂度。如果您使用here所述的优化矩阵乘法,您可以进一步改进它。然后时间复杂度将变为O(log k * n log 2 7 )。
编辑根据Antoine的要求,我解释了为什么这个算法真正起作用的解释:
我将通过归纳证明该算法。归纳的基础是显而易见的:最初我在矩阵中有长度为1的路径数。
我们假设,如果我将矩阵提升到k
的幂,k
的幂,我在mat[i][j]
中的长度为k
的路径数量为i
j
和k + 1
。
现在让我们考虑下一步k + 1
。很明显,每个长度为k
的路径都包含长度为k + 1
的前缀和一条边。这基本上意味着长度mat_pow_k
的路径可以通过(这里我用k
表示提升到n
幂的矩阵来计算
num_paths(x,y,k + 1)= sum i = 0 i< n mat_pow_k [x] [i] * mat [i] [y]
再次:mat[i][y]
是图中顶点的数量。这可能需要一段时间才能理解,但基本上只有在x
和y
之间存在直接边缘时,初始矩阵在其k + 1
单元格中才有1。我们会计算此边缘的所有可能前缀,以形成长度为k + 1
的路径。
然而,我写的最后一件事实际上是在计算mat
{{1}}的强大功能,这证明了归纳的步骤和我的陈述。
答案 1 :(得分:2)
这非常像动态编程问题:
伪代码:
memset(f, 0, sizeof(f));
f[starting_point][0] = 1;
for (int step = 0; step < n; ++step) {
for (int point = 0; point < point_num; ++point) {
for (int next_point = 0; next_point < point_num; ++ next_point) {
if (adjacent[point][next_point]) {
f[next_point][step+1] += f[point][step];
}
}
}
}
return f[starting_point][n]