【问题标题】:Count triangles (cycles of length 3) in a graph计算图中的三角形(长度为 3 的循环)
【发布时间】:2016-08-26 08:04:39
【问题描述】:

在一个有 V 个顶点和 E 个边的无向图中,你将如何计算 O(|V||E|) 中的三角形数量?我看到了算法here,但我不确定如何实现该算法以实现这种复杂性。这是该帖子中提供的代码:

for each edge (u, v):
  for each vertex w:
     if (v, w) is an edge and (w, u) is an edge:
          return true
return false

您会使用图的邻接表表示来遍历外循环中的所有边,然后使用邻接矩阵来检查内循环中是否存在 2 条边?

另外,我看到了另一种解决方案,表示为 O(|V||E|),它涉及在图上执行深度优先搜索,当你遇到来自顶点 u 的后边 (u,v) 时,你就是访问检查顶点 u 的祖父母是否是顶点 v。如果是,那么您找到了一个三角形。这个算法正确吗?如果是这样,这不是 O(|V|+|E|) 吗?在我链接到的帖子中,有一个针对所提供的广度优先搜索解决方案的反例,但根据我提出的示例,我上面概述的深度优先搜索方法似乎有效。

【问题讨论】:

  • 如果你有图的邻接表实现,迭代所有边是for (Vertex v : graph) { for (Edge e : v.Edges()) { /* do something with e */ } }。像这样的迭代是O(V+E),这将使算法在O(|V|^2 + |V||E|) 中运行。或者,您可以预处理图形并生成包含所有边的集合。
  • 您指的是我在上面发布的代码吗?如果是这样,您是否从构造邻接矩阵中得到 O(|V|^2),而从访问每个边和顶点组合中得到 O(|V||E|)?

标签: algorithm data-structures graph


【解决方案1】:

首先,请注意,该算法并没有计算三角形的数量,而是返回一个是否存在。

对于第一个算法,如果我们假设我们可以在恒定时间内查找 (a, b) 是一条边,那么分析就变得简单了。 (因为我们遍历所有边的所有顶点,并且只在恒定时间内做某事,我们得到 O(|V||E|*1)。) 可以使用 for例如hashtable/set。正如你所说,我们也可以通过使用邻接矩阵来做到这一点,我们可以通过循环所有边预先创建它,而不改变我们的总复杂性。

也许可以使用邻接表表示在边缘上循环,但遍历它可能是 O(|V|+|E|),总复杂度为 O(|V||V| + |V| |E|) 这可能比我们想要的要多。如果是这种情况,我们应该先循环,然后将所有边添加到普通集合(如列表)中。

对于您提出的 DFS 算法,问题是我们不能确定在正确的时刻遇到某个边作为后边,如下面的反例所示:

A -- B --- C -- D
      \   /     |
        E ----- F

这里如果我们从 A-B-C-E 看,然后找到后边 E-B,我们正确地找到了三角形;但是如果我们改为 A-B-C-D-F-E,则后边 E-B 和 E-C 不再满足我们的条件。

【讨论】:

  • 对,我已经修改了代码以返回三角形的数量。我怀疑您提到的有关 DFS 算法的内容,但无法拿出像您这样的图表来掌握问题。这清楚地表明这是行不通的。
  • 请注意,创建邻接矩阵可能实际上应该花费 O(|V||V|+|E|),其中 V*V 时间用于分配内存(或者我们假设这需要常数时间)。如果我们想避免这种情况,我们将边添加到哈希集中,我们可以在恒定时间内检查其成员资格。
【解决方案2】:

这是一种计算周期数的幼稚方法。 我们需要邻接矩阵形式的输入。

public int countTricycles(int [][] adj){
        int n = adj.length;
        int count = 0; 
        for(int i = 0; i < n ;i++){
            for(int j = 0; j < n; j++){
                if(adj[i][j] != 0){
                    for(int k = 0; k < n; k++){
                        if(k!=i && adj[j][k] != 0 && adj[i][k] != 0 ){
                             count++;    
                        }
                    }
                }
            }
        }
        return count/6;
    }

复杂度为 O(n^3)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    相关资源
    最近更新 更多