【问题标题】:Graph theory: Breadth First Search图论:广度优先搜索
【发布时间】:2014-02-10 18:37:38
【问题描述】:

有n个顶点由m条边连接。有些顶点是特殊的,有些是普通的。从一个顶点到另一个顶点最多有一条路径。

第一个查询: 我需要找出存在多少对直接或间接连接的特殊顶点。

我的方法: 我将应用 BFS(通过队列)以查看有多少节点以某种方式相互连接。让我在此发现的特殊顶点的数量为 n,然后对我的查询的回答将是 nC2。我将重复此操作直到所有顶点被访问。

第二个查询: 任意两个特殊顶点之间的路径上有多少个顶点。

我的方法: 在查询 1 的方法中,我将应用 BFS 来找出任意两个特殊顶点之间的路径,然后回溯并标记路径上的顶点。

问题: 顶点数可高达 50,000。因此,应用 BFS,然后我猜,对于我的时间限制(2 秒),回溯会更慢。

我有所有顶点的列表及其邻接列表。现在,在 BFS 期间在我的队列中推送顶点时,我还能以某种方式计算查询 2 的答案吗?有没有更好的方法可以用来解决问题?输入格式是这样的,我会被一一告知一个顶点是否特殊,然后我会得到关于连接两个顶点的第 i 条路径的信息。从一个顶点移动到另一个顶点最多有一条路径.

【问题讨论】:

  • 从 1 个顶点移动到另一个顶点的最多 1 条路径 --> 图是一棵树或一片森林。
  • 那些投反对票的人,有什么问题?对我来说,这是一个很好的问题。
  • 图是一片森林
  • 什么是special 顶点?
  • 我不明白为什么人们反对这个。并不是说我不费吹灰之力就可以解决问题。

标签: c++ graph-theory


【解决方案1】:

第一个查询是通过将你的森林分成几棵树来解决的。

从完整的顶点集开始,选择一个,然后从那里访问您可以访问的每个节点,直到您无法访问更多顶点。这是一棵树。对每棵树重复。

你现在有 K 个顶点包,每个顶点包含 0-j 个特殊顶点。这回答了第一个问题。

对于第二个问题,我认为一个简单的解决方案确实是对子图中的每一对顶点到另一个顶点之间的路径进行 BFS。

您还可以利用子图的树特性。这个问题:How to find the shortest simple path in a Tree in a linear time? 提到它。 (不过我还没有真正深入研究过)

【讨论】:

  • 是否可以通过队列使用 BFS 将我的森林分割成树,是否足够快且足够好?
  • 将森林一分为二是 o(n)。您只需访问所有节点,每个节点只访问一次。我看不出它怎么能更快(即你怎么能在不访问每个节点至少一次的情况下分割森林?)
  • 对于第二个问题,我认为这还不够快。但这也取决于查询的数量;如果查询的数量很大,大约 10^3,那么它将失败..
  • 是的,对于查询 1,我觉得我们不能比 O(n) 做得更好。
  • 顶点数最多为 50,000
【解决方案2】:

对于第一个查询,一轮 BFS 和您描述的一些简单计算是最佳的。

对于第二个查询,假设所有顶点都是特殊的并且图是一棵树的最坏情况,对每个查询执行 BFS 将给出 O(Q|V|) 复杂度,其中 Q 是查询的数量。如果 Q 大于 104 和 |V|,你会遇到麻烦。也大于 104

在最坏的情况下,我们基本上是在解决所有对最短路径问题,但在树/森林上。当 |V|小,我们可以在所有节点上进行 BFS,这导致 O(|V|2) 算法。但是,有一个更快的算法:

  • 读取所有第二类查询并将所有对存储在集合 S 中。
  • 对于森林中的每棵树:
    • 为当前树选择一个根节点。计算根节点到当前树中所有其他节点的距离(无论是否特殊)。
    • 为所有被查询的节点对计算最低共同祖先 (LCA)(存储在集合 S 中)。这可以通过Tarjan's offline LCA algorithm 完成。
    • 计算一对节点之间的距离:dist(root, a) + dist(root, b) - dist(root, lca(a,b))

【讨论】:

  • 如果我设法从树上移除所有叶子,我会不会只剩下特殊顶点和普通顶点,每个普通顶点肯定会位于两个特殊顶点之间的路径上?
  • @CPPPoder:我没有告诉你从树上移除所有叶子,尽管它可能有助于加快速度。我为第二个问题设计的算法并不关心节点是否特殊。
  • 其实我只需要“多少”。从我的树上移除叶子会更慢吗?
【解决方案3】:

令 arr 为 bool 数组,如果 arr[i] 是特殊的则为 1,否则为 0。 find-set(i) 返回树的根节点。因此,位于同一棵树中的任何节点都返回相同的数字。

for(int i=1; i<n; i++){ 
      for(int j=i+1; j<=n; j++){
            if(arr[i]==1 && arr[j]==1){        //If both are special
                if(find-set(i)==find-set(j)){  //and both i and j belong to the same tree
                    //k++ where k is answer to the first query.
                    //bfs(i,j) and find the intermediate vertices and do ver[i]=1 for the corresponding intermediate vertex/node.
                }
            }
      }        
}

最后计算 ver 矩阵中没有 1,这是第二个查询的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    相关资源
    最近更新 更多