【问题标题】:Time complexity of DFS on graph (O(V+E)) vs DFS on matrix (3^(M*N))图上 DFS 的时间复杂度 (O(V+E)) 与矩阵上的 DFS (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)

这个比喻哪里错了?

【问题讨论】:

    标签: algorithm time-complexity depth-first-search backtracking


    【解决方案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!)) 吗?因为我们可能会访问网格中的每条唯一路径(由于已访问检查)??
    猜你喜欢
    • 2012-07-13
    • 2015-01-01
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多