-
Notifications
You must be signed in to change notification settings - Fork 293
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
36873e9
commit 022ca74
Showing
2 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Critical and Pseudo-Critical Edges in Minimum Spanning Tree | ||
|
||
This repository contains a C implementation that identifies critical and pseudo-critical edges in a Minimum Spanning Tree (MST) of a given graph. The algorithm employs Kruskal's algorithm along with a disjoint set (union-find) data structure to efficiently manage the connected components of the graph. | ||
|
||
## Table of Contents | ||
|
||
- [Problem Description](#problem-description) | ||
- [Definitions](#definitions) | ||
- [Features](#features) | ||
- [Input Format](#input-format) | ||
- [Output Format](#output-format) | ||
- [Example](#example) | ||
- [How to Compile and Run](#how-to-compile-and-run) | ||
- [Code Structure](#code-structure) | ||
- [License](#license) | ||
- [Acknowledgments](#acknowledgments) | ||
|
||
## Problem Description | ||
|
||
In a connected, undirected graph, edges play a crucial role in defining the structure of the Minimum Spanning Tree (MST). The MST is a subset of edges that connects all vertices with the minimum possible total edge weight. Understanding which edges are critical or pseudo-critical helps in network design and optimization. | ||
|
||
## Definitions | ||
|
||
- **Critical Edge**: An edge is considered critical if its removal increases the weight of the MST. This means that the MST cannot be formed without this edge. | ||
|
||
- **Pseudo-Critical Edge**: An edge is considered pseudo-critical if it can be included in the MST without affecting the total weight, but removing it does not increase the MST weight. This means that while the edge is not essential for the MST, it can be part of it without changing the overall cost. | ||
|
||
## Features | ||
|
||
- **Efficient Edge Classification**: Uses Kruskal's algorithm to determine the MST and classify edges as critical or pseudo-critical. | ||
- **Union-Find Structure**: Implements a disjoint set data structure to efficiently manage and merge connected components. | ||
- **Dynamic Input Handling**: Accepts a variable number of edges and vertices, making it adaptable to different graph sizes. | ||
|
||
## Input Format | ||
|
||
The input consists of: | ||
- An integer `n` representing the number of vertices in the graph. | ||
- An integer `m` representing the number of edges in the graph. | ||
- A 2D array `edges` where each element is an array containing three integers: the two vertices connected by the edge and the weight of the edge. | ||
|
||
### Example Input | ||
|
||
```c | ||
int n = 5; // Number of vertices | ||
int m = 7; // Number of edges | ||
int edges[7][3] = { | ||
{0, 1, 1}, // Edge from vertex 0 to vertex 1 with weight 1 | ||
{0, 2, 3}, // Edge from vertex 0 to vertex 2 with weight 3 | ||
{1, 2, 2}, // Edge from vertex 1 to vertex 2 with weight 2 | ||
{1, 3, 4}, // Edge from vertex 1 to vertex 3 with weight 4 | ||
{2, 3, 5}, // Edge from vertex 2 to vertex 3 with weight 5 | ||
{3, 4, 6}, // Edge from vertex 3 to vertex 4 with weight 6 | ||
{1, 4, 7} // Edge from vertex 1 to vertex 4 with weight 7 | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
typedef struct { | ||
int u, v, weight, index; | ||
} Edge; | ||
|
||
typedef struct { | ||
int *parent; | ||
int *rank; | ||
int n; | ||
} DisjointSet; | ||
|
||
// Function to create a disjoint set | ||
DisjointSet* createSet(int n) { | ||
DisjointSet* ds = (DisjointSet*)malloc(sizeof(DisjointSet)); | ||
ds->parent = (int*)malloc(n * sizeof(int)); | ||
ds->rank = (int*)malloc(n * sizeof(int)); | ||
ds->n = n; | ||
for (int i = 0; i < n; i++) { | ||
ds->parent[i] = i; | ||
ds->rank[i] = 0; | ||
} | ||
return ds; | ||
} | ||
|
||
// Find function with path compression | ||
int find(DisjointSet* ds, int x) { | ||
if (ds->parent[x] != x) { | ||
ds->parent[x] = find(ds, ds->parent[x]); | ||
} | ||
return ds->parent[x]; | ||
} | ||
|
||
// Union function by rank | ||
void unionSets(DisjointSet* ds, int x, int y) { | ||
int rootX = find(ds, x); | ||
int rootY = find(ds, y); | ||
if (rootX != rootY) { | ||
if (ds->rank[rootX] > ds->rank[rootY]) { | ||
ds->parent[rootY] = rootX; | ||
} else if (ds->rank[rootX] < ds->rank[rootY]) { | ||
ds->parent[rootX] = rootY; | ||
} else { | ||
ds->parent[rootY] = rootX; | ||
ds->rank[rootX]++; | ||
} | ||
} | ||
} | ||
|
||
// Compare function for sorting edges | ||
int compareEdges(const void* a, const void* b) { | ||
return ((Edge*)a)->weight - ((Edge*)b)->weight; | ||
} | ||
|
||
// Function to calculate the weight of the MST | ||
int kruskal(Edge* edges, int n, int m, int skipIndex, int includeIndex) { | ||
DisjointSet* ds = createSet(n); | ||
int weight = 0; | ||
if (includeIndex != -1) { | ||
unionSets(ds, edges[includeIndex].u, edges[includeIndex].v); | ||
weight += edges[includeIndex].weight; | ||
} | ||
for (int i = 0; i < m; i++) { | ||
if (i == skipIndex) continue; | ||
if (find(ds, edges[i].u) != find(ds, edges[i].v)) { | ||
unionSets(ds, edges[i].u, edges[i].v); | ||
weight += edges[i].weight; | ||
} | ||
} | ||
// Check if we formed a valid MST | ||
int components = 0; | ||
for (int i = 0; i < n; i++) { | ||
if (ds->parent[i] == i) components++; | ||
} | ||
free(ds->parent); | ||
free(ds->rank); | ||
free(ds); | ||
return components == 1 ? weight : -1; // Return -1 if not all nodes are connected | ||
} | ||
|
||
// Main function to find critical and pseudo-critical edges | ||
void findCriticalAndPseudoCriticalEdges(int n, int m, int edges[][3], int* returnSize, int** returnArray) { | ||
Edge* edgeList = (Edge*)malloc(m * sizeof(Edge)); | ||
for (int i = 0; i < m; i++) { | ||
edgeList[i].u = edges[i][0]; | ||
edgeList[i].v = edges[i][1]; | ||
edgeList[i].weight = edges[i][2]; | ||
edgeList[i].index = i; | ||
} | ||
|
||
// Sort edges by weight | ||
qsort(edgeList, m, sizeof(Edge), compareEdges); | ||
|
||
// Find the weight of the MST without any edges removed | ||
int mstWeight = kruskal(edgeList, n, m, -1, -1); | ||
|
||
int* criticalEdges = (int*)malloc(m * sizeof(int)); | ||
int* pseudoCriticalEdges = (int*)malloc(m * sizeof(int)); | ||
int criticalCount = 0; | ||
int pseudoCount = 0; | ||
|
||
for (int i = 0; i < m; i++) { | ||
// Check for critical edge | ||
if (kruskal(edgeList, n, m, i, -1) > mstWeight) { | ||
criticalEdges[criticalCount++] = edgeList[i].index; | ||
} else if (kruskal(edgeList, n, m, -1, i) == mstWeight) { | ||
// Check for pseudo-critical edge | ||
pseudoCriticalEdges[pseudoCount++] = edgeList[i].index; | ||
} | ||
} | ||
|
||
// Prepare |