Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Bron-Kerbosch algorithm to BackTracking algos #1592

Merged
merged 1 commit into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions Backtracking Algorithms/Bron-Kerbosch Algorithm/Program.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTICES 100

// Function to print a maximal clique
void printClique(int *clique, int size) {
printf("Maximal Clique: ");
for (int i = 0; i < size; i++) {
printf("%d ", clique[i]);
}
printf("\n");
}

// Bron-Kerbosch algorithm
void bronKerbosch(int *R, int r_size, int *P, int p_size, int *X, int x_size, int graph[MAX_VERTICES][MAX_VERTICES]) {
if (p_size == 0 && x_size == 0) {
printClique(R, r_size);
return;
}

for (int i = 0; i < p_size; i++) {
int v = P[i];

// Create new sets for R, P, and X
int newR[MAX_VERTICES];
int newP[MAX_VERTICES];
int newX[MAX_VERTICES];
int new_r_size = r_size + 1;
int new_p_size = 0, new_x_size = 0;

// Add v to R
newR[0] = v;

// Add vertices adjacent to v to newP and newX
for (int j = 0; j < MAX_VERTICES; j++) {
if (graph[v][j]) {
if (j < p_size) {
newP[new_p_size++] = j; // Add to newP
}
if (j < x_size) {
newX[new_x_size++] = j; // Add to newX
}
}
}

// Combine R and P and recursively call the algorithm
for (int j = 0; j < r_size; j++) {
newR[j + 1] = R[j]; // Combine R
}

bronKerbosch(newR, new_r_size, newP, new_p_size, newX, new_x_size, graph);

// Update P and X
for (int j = 0; j < p_size; j++) {
if (P[j] == v) {
// Remove v from P
for (int k = j; k < p_size - 1; k++) {
P[k] = P[k + 1];
}
p_size--;
break;
}
}
// Add v to X
X[x_size++] = v;
}
}

// Main function
int main() {
int graph[MAX_VERTICES][MAX_VERTICES] = {0}; // Adjacency matrix
int n; // Number of vertices

// Define the graph
printf("Enter number of vertices: ");
scanf("%d", &n);

printf("Enter the adjacency matrix:\n");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &graph[i][j]);
}
}

// Initialize R, P, and X
int R[MAX_VERTICES] = {0}; // Current clique
int P[MAX_VERTICES]; // Potential candidates
int X[MAX_VERTICES]; // Excluded vertices
int p_size = 0;

// Initialize P with all vertices
for (int i = 0; i < n; i++) {
P[p_size++] = i;
}

// Call the Bron-Kerbosch algorithm
bronKerbosch(R, 0, P, p_size, X, 0, graph);

return 0;
}
51 changes: 51 additions & 0 deletions Backtracking Algorithms/Bron-Kerbosch Algorithm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Bron-Kerbosch Algorithm

The **Bron-Kerbosch algorithm** is a backtracking algorithm used to find all maximal cliques in an undirected graph. A clique is a subset of vertices, all of which are adjacent to each other, and a maximal clique is a clique that cannot be extended by including an adjacent vertex. This algorithm is known for its recursive nature and efficiency in finding cliques in graphs without needing to search through all vertex subsets.

## Definition

The Bron-Kerbosch algorithm is a **recursive backtracking algorithm** that enumerates all maximal cliques in an undirected graph. By maintaining three sets during recursion, the algorithm explores all potential cliques and ensures that each maximal clique is discovered only once.

## Characteristics

- **Exactness**: The algorithm is exact and produces all maximal cliques without duplication.
- **Recursiveness**: It uses recursive backtracking with sets of vertices to manage the state at each step.
- **Efficiency**: The algorithm is highly efficient, especially for sparse graphs.
- **Pivoting**: The pivoting technique can be used to reduce the number of recursive calls, optimizing performance by reducing the search space.

## Time Complexity

The time complexity of the Bron-Kerbosch algorithm varies depending on the implementation:

- **Without pivoting**: , where \(n\) is the number of vertices.
- **With pivoting**: The worst-case complexity remains `O(3^(n/3))`, but pivoting reduces the number of recursive calls in practice, making the algorithm faster on average.

## Space Complexity

The space complexity is **O(n + E)**, where \(n\) is the number of vertices and \(E\) is the number of edges. This is primarily due to storing the adjacency list or matrix and maintaining three sets (R, P, and X) in each recursive call.

## Approach

The Bron-Kerbosch algorithm follows these steps:

1. **Initialize three sets**:
- **R**: The growing clique being constructed.
- **P**: The set of vertices that can still be added to the current clique.
- **X**: The set of vertices that have already been considered for the current clique.

2. **Recursive Backtracking**:
- At each step, choose a vertex from \(P\) and add it to \(R\), forming a new potential clique.
- Recur with updated sets:
- **R** includes the chosen vertex.
- **P** is restricted to vertices adjacent to the new vertex.
- **X** is updated to avoid revisiting vertices.

3. **Base Case**:
- If both \(P\) and \(X\) are empty, \(R\) is a maximal clique.

4. **Pivot Optimization (Optional)**:
- Choose a pivot vertex to minimize the number of recursive calls by excluding vertices that are unlikely to form new cliques.

## Summary

The Bron-Kerbosch algorithm efficiently finds all maximal cliques in a graph, making it useful in various fields such as social network analysis and bioinformatics. With optional pivoting, it is adaptable to dense and sparse graphs alike, offering high-performance clique detection for applications requiring maximal clique identification.
Loading