在具有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 |)吗?在我链接到的帖子中,提供了广度优先搜索解决方案的反例,但基于我提出的示例,似乎我在上面概述的深度优先搜索方法有效。
答案 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)。