在图

时间:2016-08-26 08:04:39

标签: algorithm data-structures graph

在具有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,v)时,你就是访问检查顶点u的祖父是否是顶点v。如果是,那么你找到了一个三角形。这个算法是否正确?如果是这样,这不是O(| V | + | E |)吗?在我链接到的帖子中,提供了广度优先搜索解决方案的反例,但基于我提出的示例,似乎我在上面概述的深度优先搜索方法有效。

2 个答案:

答案 0 :(得分:2)

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

对于第一种算法,如果我们假设我们可以在恒定时间内查找(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就不再满足我们的条件。

答案 1 :(得分:1)

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

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)。