无向图中的三角形数
给定一个无向简单图,我们需要找出它可以有多少个三角形。例如下图有 2 个三角形。
令 A[][] 为图的邻接矩阵表示。如果我们计算 A 3 ,那么无向图中的三角形数等于 trace(A 3 ) / 6。其中 trace(A) 是矩阵 A 的主对角线上的元素之和。
Trace of a graph represented as adjacency matrix A[V][V] is,
trace(A[V][V]) = A[0][0] + A[1][1] + .... + A[V-1][V-1]
Count of triangles = trace(A3) / 6
下面是上述公式的实现。
C++
// A C++ program for finding
// number of triangles in an
// Undirected Graph. The program
// is for adjacency matrix
// representation of the graph
#include
using namespace std;
// Number of vertices in the graph
#define V 4
// Utility function for matrix
// multiplication
void multiply(int A[][V], int B[][V], int C[][V])
{
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
C[i][j] = 0;
for (int k = 0; k < V; k++)
C[i][j] += A[i][k]*B[k][j];
}
}
}
// Utility function to calculate
// trace of a matrix (sum of
// diagonal elements)
int getTrace(int graph[][V])
{
int trace = 0;
for (int i = 0; i < V; i++)
trace += graph[i][i];
return trace;
}
// Utility function for calculating
// number of triangles in graph
int triangleInGraph(int graph[][V])
{
// To Store graph^2
int aux2[V][V];
// To Store graph^3
int aux3[V][V];
// Initialising aux
// matrices with 0
for (int i = 0; i < V; ++i)
for (int j = 0; j < V; ++j)
aux2[i][j] = aux3[i][j] = 0;
// aux2 is graph^2 now printMatrix(aux2);
multiply(graph, graph, aux2);
// after this multiplication aux3 is
// graph^3 printMatrix(aux3);
multiply(graph, aux2, aux3);
int trace = getTrace(aux3);
return trace / 6;
}
// driver code
int main()
{
int graph[V][V] = {{0, 1, 1, 0},
{1, 0, 1, 1},
{1, 1, 0, 1},
{0, 1, 1, 0}
};
printf("Total number of Triangle in Graph : %d\n",
triangleInGraph(graph));
return 0;
}
Java
// Java program to find number
// of triangles in an Undirected
// Graph. The program is for
// adjacency matrix representation
// of the graph
import java.io.*;
class Directed
{
// Number of vertices in
// the graph
int V = 4;
// Utility function for
// matrix multiplication
void multiply(int A[][], int B[][],
int C[][])
{
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
C[i][j] = 0;
for (int k = 0; k < V;
k++)
{
C[i][j] += A[i][k]*
B[k][j];
}
}
}
}
// Utility function to calculate
// trace of a matrix (sum of
// diagonal elements)
int getTrace(int graph[][])
{
int trace = 0;
for (int i = 0; i < V; i++)
{
trace += graph[i][i];
}
return trace;
}
// Utility function for
// calculating number of
// triangles in graph
int triangleInGraph(int graph[][])
{
// To Store graph^2
int[][] aux2 = new int[V][V];
// To Store graph^3
int[][] aux3 = new int[V][V];
// Initialising aux matrices
// with 0
for (int i = 0; i < V; ++i)
{
for (int j = 0; j < V; ++j)
{
aux2[i][j] = aux3[i][j] = 0;
}
}
// aux2 is graph^2 now
// printMatrix(aux2)
multiply(graph, graph, aux2);
// after this multiplication aux3
// is graph^3 printMatrix(aux3)
multiply(graph, aux2, aux3);
int trace = getTrace(aux3);
return trace / 6;
}
// Driver code
public static void main(String args[])
{
Directed obj = new Directed();
int graph[][] = { {0, 1, 1, 0},
{1, 0, 1, 1},
{1, 1, 0, 1},
{0, 1, 1, 0}
};
System.out.println("Total number of Triangle in Graph : "+
obj.triangleInGraph(graph));
}
}
// This code is contributed by Anshika Goyal.
Python3
# A Python3 program for finding number of
# triangles in an Undirected Graph. The
# program is for adjacency matrix
# representation of the graph
# Utility function for matrix
# multiplication
def multiply(A, B, C):
global V
for i in range(V):
for j in range(V):
C[i][j] = 0
for k in range(V):
C[i][j] += A[i][k] * B[k][j]
# Utility function to calculate
# trace of a matrix (sum of
# diagonal elements)
def getTrace(graph):
global V
trace = 0
for i in range(V):
trace += graph[i][i]
return trace
# Utility function for calculating
# number of triangles in graph
def triangleInGraph(graph):
global V
# To Store graph^2
aux2 = [[None] * V for i in range(V)]
# To Store graph^3
aux3 = [[None] * V for i in range(V)]
# Initialising aux
# matrices with 0
for i in range(V):
for j in range(V):
aux2[i][j] = aux3[i][j] = 0
# aux2 is graph^2 now printMatrix(aux2)
multiply(graph, graph, aux2)
# after this multiplication aux3 is
# graph^3 printMatrix(aux3)
multiply(graph, aux2, aux3)
trace = getTrace(aux3)
return trace // 6
# Driver Code
# Number of vertices in the graph
V = 4
graph = [[0, 1, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 1],
[0, 1, 1, 0]]
print("Total number of Triangle in Graph :",
triangleInGraph(graph))
# This code is contributed by PranchalK
C#
// C# program to find number
// of triangles in an Undirected
// Graph. The program is for
// adjacency matrix representation
// of the graph
using System;
class GFG
{
// Number of vertices
// in the graph
int V = 4;
// Utility function for
// matrix multiplication
void multiply(int [,]A, int [,]B,
int [,]C)
{
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
C[i, j] = 0;
for (int k = 0; k < V;
k++)
{
C[i, j] += A[i, k]*
B[k, j];
}
}
}
}
// Utility function to
// calculate trace of
// a matrix (sum of
// diagonal elements)
int getTrace(int [,]graph)
{
int trace = 0;
for (int i = 0; i < V; i++)
{
trace += graph[i, i];
}
return trace;
}
// Utility function for
// calculating number of
// triangles in graph
int triangleInGraph(int [,]graph)
{
// To Store graph^2
int[,] aux2 = new int[V, V];
// To Store graph^3
int[,] aux3 = new int[V, V];
// Initialising aux matrices
// with 0
for (int i = 0; i < V; ++i)
{
for (int j = 0; j < V; ++j)
{
aux2[i, j] = aux3[i, j] = 0;
}
}
// aux2 is graph^2 now
// printMatrix(aux2)
multiply(graph, graph, aux2);
// after this multiplication aux3
// is graph^3 printMatrix(aux3)
multiply(graph, aux2, aux3);
int trace = getTrace(aux3);
return trace / 6;
}
// Driver code
public static void Main()
{
GFG obj = new GFG();
int [,]graph = {{0, 1, 1, 0},
{1, 0, 1, 1},
{1, 1, 0, 1},
{0, 1, 1, 0}};
Console.WriteLine("Total number of " +
"Triangle in Graph : "+
obj.triangleInGraph(graph));
}
}
// This code is contributed by anuj_67.
Javascript
C++
#include
#include
#include
#include
#include
#include
using namespace std;
#define V 4
int main()
{
// Graph represented as adjacency matrix
int graph[][V] = {{0, 1, 1, 0},
{1, 0, 1, 1},
{1, 1, 0, 1},
{0, 1, 1, 0}};
// create the adjacency list of the graph (as bit masks)
// set the bits at positions [i][j] & [j][i] to 1, if there is an undirected edge between i and j
vector> Bitset_Adj_List(V);
for (int i = 0; i < V;i++)
for (int j = 0; j < V;j++)
if(graph[i][j])
Bitset_Adj_List[i][j] = 1,
Bitset_Adj_List[j][i] = 1;
int ans = 0;
for (int i = 0; i < V;i++)
for (int j = 0; j < V;j++)
// if i & j are adjacent
// compute the number of nodes that are adjacent to i & j
if(Bitset_Adj_List[i][j] == 1 && i != j){
bitset Mask = Bitset_Adj_List[i] & Bitset_Adj_List[j];
ans += Mask.count();
}
// divide the answer by 6 to avoid duplicates
ans /= 6;
cout << "The number of Triangles in the Graph is : " << ans;
// This code is contributed
// by Gatea David
}
输出:
Total number of Triangle in Graph : 2
这是如何运作的?
如果我们为图的邻接矩阵表示计算 A n ,则值 A n [i][j] 表示图中顶点 i 到 j 之间的不同游走的数量。在 A 3中,我们得到每对顶点之间长度为 3 的所有不同路径。
三角形是长度为三的循环路径,即在同一顶点开始和结束。所以 A 3 [i][i] 表示一个以顶点 i 开始和结束的三角形。由于三角形有三个顶点,并且每个顶点都计算在内,所以我们需要将结果除以 3。此外,由于图是无向图,每个三角形都是 ipqj 和 iqpj 的两倍,所以我们也除以 2。因此,三角形的数量为 trace(A 3 ) / 6。
时间复杂度:
上述算法的时间复杂度为 O(V 3 ),其中 V 是图中的顶点数,我们可以使用 Strassen 的矩阵乘法算法将性能提高到 O(V 2.8074 )。
另一种方法:使用 Bitsets 作为邻接列表。
- 对于图中的每个节点,计算相应的邻接列表作为位掩码。
- 如果两个节点 i 和 j 相邻,则计算与 i 和 j 相邻的节点数并将其添加到答案中。
- 最后,将答案除以 6 以避免重复。
为了计算与两个节点 i & j 相邻的节点数,我们在 i 和 j 的邻接表上使用按位运算& (and),然后计算个数。
下面是上述方法的实现:
C++
#include
#include
#include
#include
#include
#include
using namespace std;
#define V 4
int main()
{
// Graph represented as adjacency matrix
int graph[][V] = {{0, 1, 1, 0},
{1, 0, 1, 1},
{1, 1, 0, 1},
{0, 1, 1, 0}};
// create the adjacency list of the graph (as bit masks)
// set the bits at positions [i][j] & [j][i] to 1, if there is an undirected edge between i and j
vector> Bitset_Adj_List(V);
for (int i = 0; i < V;i++)
for (int j = 0; j < V;j++)
if(graph[i][j])
Bitset_Adj_List[i][j] = 1,
Bitset_Adj_List[j][i] = 1;
int ans = 0;
for (int i = 0; i < V;i++)
for (int j = 0; j < V;j++)
// if i & j are adjacent
// compute the number of nodes that are adjacent to i & j
if(Bitset_Adj_List[i][j] == 1 && i != j){
bitset Mask = Bitset_Adj_List[i] & Bitset_Adj_List[j];
ans += Mask.count();
}
// divide the answer by 6 to avoid duplicates
ans /= 6;
cout << "The number of Triangles in the Graph is : " << ans;
// This code is contributed
// by Gatea David
}
The number of Triangles in the Graph is : 2
时间复杂度:首先,我们有两个嵌套循环 O(V 2 ) 通过 Bitset 操作 & 和 count 流动,两者的时间复杂度都是 O(V / Word RAM),其中 V = 图中的节点数和 Word RAM通常是 32 或 64。所以最终的时间复杂度是 O(V 2 * V / 32) 或 O(V 3 )。
参考:
http://www.d.umn.edu/math/Technical%20Reports/Technical%20Reports%202007-/TR%202012/yang.pdf
有向图和无向图中的三角形数。