图上 DFS 的时间复杂度 (O(V+E)) 与矩阵上的 DFS (3^(M*N))

Posted

技术标签:

【中文标题】图上 DFS 的时间复杂度 (O(V+E)) 与矩阵上的 DFS (3^(M*N))【英文标题】:Time complexity of DFS on graph (O(V+E)) vs DFS on matrix (3^(M*N)) 【发布时间】:2021-06-07 20:36:50 【问题描述】:

如果听起来太不合逻辑,请道歉。

今天在解决一些竞争性问题时,我突然想到了一个奇怪的想法。

我们说 DFS 的时间复杂度是 O(V+E),因为我们只遍历邻接表一次,即对于我们考虑其边的每个节点。

但是,当对大小为 MN 的矩阵执行 dfs 时。 我们可以说一个矩阵是一个具有 MN 个顶点的图(每个单元格都是一个顶点),并且它的相邻单元格有一条边 ==> 每个顶点都有 4 条边(为简单起见,让我们忽略边界情况)

然后当我们做 DFS 时

    private void dfs(int grid[][], int i, int j, int m, int n) 
        if(i<0 || j<0 || i>m || j>n || visited[i][j])
            return;
        visited[i][j] = true;
        dfs(grid, i+1, j, m, n);
        dfs(grid, i-1, j, m, n);
        dfs(grid, i, j-1, m, n);
        dfs(grid, i, j+1, m, n)
        visited[i][j] = false;
    

==> 在图形术语中它的 O(V+E) => O(MN + 4MN) => O(5MN) => O(MN) ==> 但是时间复杂度是 4^(MN)

这个比喻哪里错了?

【问题讨论】:

【参考方案1】:

O(V+E) 的复杂度只有在每个节点都被访问一次时才成立。在您的代码中,您访问一个节点并将其标记为已访问,但在父节点完成后,您将其标记为未访问。

所以当下一个孩子被处理时,它会再次访问它的父母。如果一个父节点有 4 个子节点,它的子节点将额外访问 1 次,每个节点访问 4 次,复杂度为 4x4x...(MN) = 4^MN。

你删除visited[i][j] = false,你会看到一个节点被访问过一次就再也不会被访问了,复杂度是O(节点数) = O(MN)

【讨论】:

(i, j) 处的节点不会立即被其自己的子节点重新访问 -- visited[i][j] 那时仍然是 true,因此尝试这样做的递归调用会立即返回.但稍后会再次多次被来自尚未访问其父节点的起始顶点的路径访问。 3^(M*N) 是配置数量的上限,但每个配置需要 1 到 M*N 步才能生成。 感谢@SomeDude 的回答 @SomeDude 它的 3^(MN) 精确而不是 4^(MN) 因为在我们执行的四个递归中,1 总是导致基本条件,因为它已经访问过(因此此递归的恒定时间)。因此,对于每个单元格,我们有效地进行 3 次递归调用 时间复杂度不应该是 O((n + m)!/(n!m!)) 吗?因为我们可能会访问网格中的每条唯一路径(由于已访问检查)??

以上是关于图上 DFS 的时间复杂度 (O(V+E)) 与矩阵上的 DFS (3^(M*N))的主要内容,如果未能解决你的问题,请参考以下文章

graph

深度优先搜索(DFS)(Java)

dfs - 判断图上连个点之间是否可达

简谈DFS

拓扑排序

常见的算法和数据结构的时间复杂度和空间复杂度