【问题标题】:Graph traversal of n stepsn 步的图遍历
【发布时间】:2012-05-07 22:25:33
【问题描述】:

给定一个像这样的简单无向图:

从 D、A、B 或 C (V_start) 开始——我必须计算从 n 的起点 (V_start) 到起点 (V_start) 的可能路径数步骤,每个边和顶点可以被无限次访问。

我正在考虑进行深度优先搜索,当steps > n || (steps == n && vertex != V_start) 时停止,但是,如果,例如n = 1000000,这将变得相当昂贵。我的下一个想法使我将 DFS 与动态编程结合起来,但是,这就是我遇到的问题。

(这不是家庭作业,只是为了学习,我被困在玩图表和算法。)

我将如何在合理的时间内使用大型 n 解决这个问题?

【问题讨论】:

  • 你可以在一条路径中多次使用边吗?
  • 那么路径是无限的?
  • @aib:由于路径的长度是有限的,在某些情况下只有大量的组合:)
  • 啊,n 步骤。错过了。

标签: c++ c algorithm graph


【解决方案1】:

这个任务是通过矩阵乘法来解决的。

创建包含 0 和 1 的矩阵 nxn(如果有从 ij 的路径,则为单元格 mat[i][j])。将此矩阵乘以自身k 次(考虑使用快速矩阵求幂)。然后在矩阵的单元格mat[i][j] 中,您有长度为k 的路径数,从i 开始,以j 结束。

注意:快速矩阵求幂与快速求幂基本相同,只是将数字乘以矩阵。

注意2:假设n 是图中的顶点数。然后我在这里提出的算法运行时间复杂度为 O(log k * n3),内存复杂度为 O(n 2)。如果您使用如here 所述的优化矩阵乘法,则可以进一步改进它。那么时间复杂度会变成O(log k * nlog27)。


编辑应 Antoine 的要求,我解释了为什么该算法确实有效:

我将通过归纳证明算法。归纳的基础很明显:最初我在矩阵中有长度为 1 的路径数。

让我们假设直到k 的幂,如果我将矩阵提升到k 的幂,我在mat[i][j] 中有长度为k 的路径数在ij 之间。

现在让我们考虑下一步k + 1。很明显,每条长度为k + 1 的路径都由长度为k 的前缀和一条边组成。这基本上意味着长度为k + 1 的路径可以通过以下方式计算(这里我用mat_pow_k 表示矩阵提升到kth 次方)

num_paths(x, y, k + 1) = sumi=0i mat_pow_k[x][i] * mat[i][y]

同样:n 是图中的顶点数。这可能需要一段时间才能理解,但基本上只有在xy 之间存在直接边缘时,初始矩阵在其mat[i][y] 单元格中才具有1。我们计算这种边缘的所有可能前缀以形成长度为k + 1的路径。

然而我写的最后一件事实际上是计算matk + 1st幂,这证明了归纳的步骤和我的陈述。

【讨论】:

  • @Antoine Done - 我通过归纳添加了证明,希望它足够容易理解。
  • 感谢您的精彩回答。
  • 那么当 N = 10^6 时,我们需要一个由 10^12 个 64 位计数器组成的矩阵...也许 N 和 K 交换了...
  • @chac 当然是真的。我从未说过我的解决方案适用于所有情况。但是对于 N=10^6,我可以想到一个图表,直到世界末日你都无法阅读......
  • 是的,应该是指数级的,但是“动态规划的 DFS”可以解决这个问题。对不起,我不知道细节......
【解决方案2】:

这很像一个动态规划问题:

  1. 将 a f[n][m] 定义为从起点到点 n 的路径数,步长为 m
  2. 从每个点 n 到其相邻的 k,您有公式:f[k][m+1] = f[k][m+1] + f[n][m]
  3. 初始化时,所有的f[n][m]都会为0,但是f[starting_point][0] = 1
  4. 因此您可以计算最终结果

伪代码:

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]

【讨论】:

    猜你喜欢
    • 2015-07-15
    • 1970-01-01
    • 2012-04-19
    • 2011-06-10
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    相关资源
    最近更新 更多