Associates a cost, distance, capacity or time with a connection.
đ¸ď¸ Advanced Graph Algorithms
Master minimum spanning trees, shortest paths, directed acyclic graphs, strongly connected components and maximum flow through complete algorithms, C programs, visualization and line-by-line tracing.
đŻ Learning Objectives
- Distinguish directed, undirected, weighted, connected and residual graphs.
- Construct minimum spanning trees using Prim and Kruskal.
- Compute single-source and all-pairs shortest paths.
- Detect negative cycles using BellmanâFord.
- Produce a topological ordering and identify cycles in a directed graph.
- Find strongly connected components using Kosaraju.
- Calculate maximum flow using EdmondsâKarp residual networks.
- Trace every loop, comparison, relaxation and structural update in C.
đ§ 1. Advanced Graph Foundations
Partitions vertices into two sets; crossing edges connect the sets.
Improves a known distance through an edge when a cheaper route exists.
Shows how much additional flow can be sent or cancelled.
| Representation | Space | Check edge | Enumerate neighbors |
|---|---|---|---|
| Adjacency matrix | O(V²) | O(1) | O(V) |
| Adjacency list | O(V + E) | O(deg u) | O(deg u) |
| Edge list | O(E) | O(E) | O(E) |
đ 2. Minimum Spanning Trees
A spanning tree of a connected undirected graph contains all V vertices, exactly V â 1 edges and no cycle. A minimum spanning tree has the minimum possible total edge weight.
Primâs Algorithm
Grow one tree. Repeatedly choose the lightest edge crossing from the visited set to an unvisited vertex.
- Set every key to â and the source key to 0.
- Select the unused vertex with the minimum key.
- Add it to the tree.
- Relax its incident edges.
Kruskalâs Algorithm
Grow a forest. Process edges in nondecreasing weight and accept an edge only when it joins different components.
- Sort all edges.
- Find both component roots.
- Skip an edge that creates a cycle.
- Union accepted components.
| Algorithm | Main structure | Time | Best fit |
|---|---|---|---|
| Prim | Priority queue / key array | O(E log V) | Dense or adjacency-list graphs |
| Kruskal | Sorted edges + DSU | O(E log E) | Sparse edge-list graphs |
đŁď¸ 3. Shortest-Path Algorithms
Dijkstra
Greedy single-source shortest paths. Requires nonnegative edge weights.
BellmanâFord
Relaxes every edge V â 1 times and detects reachable negative cycles.
FloydâWarshall
Dynamic programming for all-pairs shortest paths using each vertex as an intermediate.
Relaxation Algorithm
- Read edge u â v with weight w.
- Verify that distance[u] is finite.
- Compare distance[u] + w with distance[v].
- If it is smaller, update distance[v] and predecessor[v].
| Algorithm | Negative edges | Negative-cycle detection | Time |
|---|---|---|---|
| Dijkstra | No | No | O(E log V) |
| BellmanâFord | Yes | Yes | O(VE) |
| FloydâWarshall | Yes | Via dist[i][i] < 0 | O(VÂł) |
đ§Š 4. Directed Graph Algorithms
Kahn Topological Sort
Place all zero-indegree vertices in a queue. Remove one, output it and reduce every outgoing neighborâs indegree. Fewer than V outputs proves a cycle.
Kosaraju SCC
Run DFS to record decreasing finish time, transpose every edge, then process vertices in finish-time order to reveal strongly connected components.
đ 5. Maximum Flow
A feasible flow respects capacity constraints and flow conservation. FordâFulkerson repeatedly augments an sât path. EdmondsâKarp chooses the shortest augmenting path in number of edges using BFS.
Build residual graph
Initial residual capacity equals original capacity.
Run BFS
Find a residual path from source to sink.
Bottleneck
Take the minimum residual capacity on the path.
Augment
Decrease forward capacity and increase reverse capacity.
đť 6. Complete C Programs
Primâs Minimum Spanning Tree View program
#include <stdio.h>
#include <limits.h>
#define V 6
int minimumKey(int key[], int used[]) {
int best = INT_MAX;
int vertex = -1;
for (int i = 0; i < V; i++) { /* prim select loop */
if (!used[i] && key[i] < best) { /* prim select compare */
best = key[i];
vertex = i;
}
}
return vertex; /* prim select result */
}
void prim(int graph[V][V]) {
int parent[V];
int key[V];
int used[V] = {0};
for (int i = 0; i < V; i++) { /* prim initialize */
key[i] = INT_MAX;
parent[i] = -1;
}
key[0] = 0;
for (int count = 0; count < V; count++) { /* prim main loop */
int u = minimumKey(key, used); /* prim choose */
if (u == -1)
break;
used[u] = 1; /* prim add vertex */
for (int v = 0; v < V; v++) { /* prim edge loop */
if (
graph[u][v] &&
!used[v] &&
graph[u][v] < key[v]
) { /* prim relax compare */
key[v] = graph[u][v]; /* prim relax update */
parent[v] = u;
}
}
}
int total = 0;
for (int v = 1; v < V; v++) {
if (parent[v] != -1) {
printf(
"%c-%c %d\n",
'A' + parent[v],
'A' + v,
graph[v][parent[v]]
);
total += graph[v][parent[v]];
}
}
printf("MST cost = %d\n", total); /* prim output */
}
int main(void) {
int graph[V][V] = {
{0, 4, 2, 0, 0, 0},
{4, 0, 1, 5, 0, 0},
{2, 1, 0, 8, 10, 0},
{0, 5, 8, 0, 2, 6},
{0, 0, 10, 2, 0, 3},
{0, 0, 0, 6, 3, 0}
};
prim(graph);
return 0;
}
Kruskalâs Minimum Spanning Tree View program
#include <stdio.h>
#include <stdlib.h>
#define V 6
#define E 9
typedef struct {
int u;
int v;
int w;
} Edge;
int compare(const void *first, const void *second) {
const Edge *a = first;
const Edge *b = second;
return a->w - b->w;
}
int find(int parent[], int vertex) {
if (parent[vertex] != vertex) {
parent[vertex] =
find(parent, parent[vertex]);
}
return parent[vertex]; /* kruskal find */
}
void unite(
int parent[],
int rank[],
int first,
int second
) {
first = find(parent, first);
second = find(parent, second);
if (rank[first] < rank[second]) {
parent[first] = second;
} else if (rank[first] > rank[second]) {
parent[second] = first;
} else {
parent[second] = first;
rank[first]++;
}
}
int main(void) {
Edge edges[E] = {
{0, 1, 4},
{0, 2, 2},
{1, 2, 1},
{1, 3, 5},
{2, 3, 8},
{2, 4, 10},
{3, 4, 2},
{3, 5, 6},
{4, 5, 3}
};
int parent[V];
int rank[V] = {0};
int selected = 0;
int total = 0;
for (int i = 0; i < V; i++) { /* kruskal initialize */
parent[i] = i;
}
qsort(
edges,
E,
sizeof(Edge),
compare
); /* kruskal sort */
for (
int i = 0;
i < E && selected < V - 1;
i++
) { /* kruskal edge loop */
Edge edge = edges[i]; /* kruskal consider */
int firstRoot =
find(parent, edge.u);
int secondRoot =
find(parent, edge.v);
if (firstRoot != secondRoot) { /* kruskal cycle check */
printf(
"%c-%c %d\n",
'A' + edge.u,
'A' + edge.v,
edge.w
);
total += edge.w;
selected++; /* kruskal accept */
unite(
parent,
rank,
firstRoot,
secondRoot
);
}
}
printf("MST cost = %d\n", total); /* kruskal output */
return 0;
}
Dijkstraâs Shortest Paths View program
#include <stdio.h>
#include <limits.h>
#define V 6
int minimumDistance(
int distance[],
int completed[]
) {
int best = INT_MAX;
int vertex = -1;
for (int i = 0; i < V; i++) { /* dijkstra select loop */
if (
!completed[i] &&
distance[i] < best
) { /* dijkstra select compare */
best = distance[i];
vertex = i;
}
}
return vertex; /* dijkstra select result */
}
void dijkstra(
int graph[V][V],
int source
) {
int distance[V];
int parent[V];
int completed[V] = {0};
for (int i = 0; i < V; i++) { /* dijkstra initialize */
distance[i] = INT_MAX;
parent[i] = -1;
}
distance[source] = 0;
for (
int count = 0;
count < V;
count++
) { /* dijkstra main loop */
int u = minimumDistance(
distance,
completed
); /* dijkstra choose */
if (u == -1)
break;
completed[u] = 1; /* dijkstra settle */
for (int v = 0; v < V; v++) { /* dijkstra edge loop */
if (
graph[u][v] &&
!completed[v] &&
distance[u] != INT_MAX
) { /* dijkstra edge check */
int candidate =
distance[u] +
graph[u][v];
if (
candidate < distance[v]
) { /* dijkstra relax compare */
distance[v] =
candidate; /* dijkstra relax update */
parent[v] = u;
}
}
}
}
for (int i = 0; i < V; i++) {
printf(
"A to %c = %d\n",
'A' + i,
distance[i]
); /* dijkstra output */
}
}
int main(void) {
int graph[V][V] = {
{0, 4, 2, 0, 0, 0},
{4, 0, 1, 5, 0, 0},
{2, 1, 0, 8, 10, 0},
{0, 5, 8, 0, 2, 6},
{0, 0, 10, 2, 0, 3},
{0, 0, 0, 6, 3, 0}
};
dijkstra(graph, 0);
return 0;
}
BellmanâFord Shortest Paths View program
#include <stdio.h>
#include <limits.h>
#define V 6
#define E 9
typedef struct {
int u;
int v;
int w;
} Edge;
int main(void) {
Edge edges[E] = {
{0, 1, 4},
{0, 2, 2},
{1, 2, -1},
{1, 3, 5},
{2, 3, 8},
{2, 4, 10},
{3, 4, 2},
{3, 5, 6},
{4, 5, 3}
};
int distance[V];
int parent[V];
for (int i = 0; i < V; i++) { /* bellman initialize */
distance[i] = INT_MAX;
parent[i] = -1;
}
distance[0] = 0;
for (
int pass = 1;
pass < V;
pass++
) { /* bellman pass loop */
int changed = 0;
for (int i = 0; i < E; i++) { /* bellman edge loop */
Edge edge =
edges[i]; /* bellman read edge */
if (
distance[edge.u] != INT_MAX &&
distance[edge.u] + edge.w
< distance[edge.v]
) { /* bellman relax compare */
distance[edge.v] =
distance[edge.u] +
edge.w; /* bellman relax update */
parent[edge.v] = edge.u;
changed = 1;
}
}
if (!changed) {
break; /* bellman early stop */
}
}
for (int i = 0; i < E; i++) { /* bellman cycle loop */
Edge edge = edges[i];
if (
distance[edge.u] != INT_MAX &&
distance[edge.u] + edge.w
< distance[edge.v]
) { /* bellman cycle check */
printf("Negative cycle\n");
return 0;
}
}
for (int i = 0; i < V; i++) {
printf(
"A to %c = %d\n",
'A' + i,
distance[i]
); /* bellman output */
}
return 0;
}
FloydâWarshall All-Pairs Shortest Paths View program
#include <stdio.h>
#define V 5
#define INF 99999
int main(void) {
int distance[V][V] = { /* floyd initialize */
{0, 3, INF, 7, INF},
{8, 0, 2, INF, INF},
{5, INF, 0, 1, INF},
{2, INF, INF, 0, 4},
{INF, INF, 1, INF, 0}
};
for (int k = 0; k < V; k++) { /* floyd k loop */
for (int i = 0; i < V; i++) { /* floyd i loop */
for (int j = 0; j < V; j++) { /* floyd j loop */
if (
distance[i][k] != INF &&
distance[k][j] != INF
) { /* floyd path check */
int through =
distance[i][k] +
distance[k][j];
if (
through < distance[i][j]
) { /* floyd relax compare */
distance[i][j] =
through; /* floyd relax update */
}
}
}
}
}
for (int i = 0; i < V; i++) { /* floyd output */
for (int j = 0; j < V; j++) {
printf(
"%5d",
distance[i][j]
);
}
printf("\n");
}
return 0;
}
Kahnâs Topological Sort View program
#include <stdio.h>
#define V 6
int main(void) {
int graph[V][V] = {
{0, 0, 0, 1, 0, 0},
{0, 0, 0, 1, 1, 0},
{0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0}
};
int indegree[V] = {0};
int queue[V];
int front = 0;
int rear = 0;
int count = 0;
for (int u = 0; u < V; u++) { /* topo indegree outer */
for (int v = 0; v < V; v++) {
if (graph[u][v]) {
indegree[v]++; /* topo indegree update */
}
}
}
for (int i = 0; i < V; i++) {
if (indegree[i] == 0) {
queue[rear++] =
i; /* topo enqueue initial */
}
}
while (front < rear) { /* topo queue loop */
int u =
queue[front++]; /* topo dequeue */
printf(
"%c ",
'A' + u
); /* topo output vertex */
count++;
for (int v = 0; v < V; v++) { /* topo edge loop */
if (graph[u][v]) {
indegree[v]--; /* topo reduce indegree */
if (indegree[v] == 0) {
queue[rear++] =
v; /* topo enqueue */
}
}
}
}
if (count != V) {
printf(
"Cycle detected"
); /* topo cycle check */
}
printf("\n");
return 0;
}
Kosaraju Strongly Connected Components View program
#include <stdio.h>
#define V 6
void firstDFS(
int vertex,
int graph[V][V],
int visited[],
int stack[],
int *top
) {
visited[vertex] = 1; /* kosa first visit */
for (int next = 0; next < V; next++) { /* kosa first edge loop */
if (
graph[vertex][next] &&
!visited[next]
) {
firstDFS(
next,
graph,
visited,
stack,
top
); /* kosa first recurse */
}
}
stack[(*top)++] =
vertex; /* kosa finish push */
}
void secondDFS(
int vertex,
int transpose[V][V],
int visited[]
) {
visited[vertex] = 1; /* kosa second visit */
printf(
"%c ",
'A' + vertex
);
for (int next = 0; next < V; next++) { /* kosa second edge loop */
if (
transpose[vertex][next] &&
!visited[next]
) {
secondDFS(
next,
transpose,
visited
); /* kosa second recurse */
}
}
}
int main(void) {
int graph[V][V] = {
{0, 1, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0},
{1, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 1, 0},
{0, 0, 0, 1, 0, 1},
{0, 0, 0, 0, 0, 0}
};
int transpose[V][V] = {{0}};
int visited[V] = {0};
int stack[V];
int top = 0;
for (int i = 0; i < V; i++) {
if (!visited[i]) {
firstDFS(
i,
graph,
visited,
stack,
&top
); /* kosa first start */
}
}
for (int u = 0; u < V; u++) {
for (int v = 0; v < V; v++) {
transpose[v][u] =
graph[u][v]; /* kosa transpose */
}
}
for (int i = 0; i < V; i++) {
visited[i] = 0;
}
while (top > 0) { /* kosa stack loop */
int vertex =
stack[--top]; /* kosa pop */
if (!visited[vertex]) {
secondDFS(
vertex,
transpose,
visited
); /* kosa component */
printf("\n");
}
}
return 0;
}
EdmondsâKarp Maximum Flow View program
#include <stdio.h>
#include <limits.h>
#define V 6
int bfs(
int residual[V][V],
int source,
int sink,
int parent[]
) {
int visited[V] = {0};
int queue[V];
int front = 0;
int rear = 0;
queue[rear++] = source;
visited[source] = 1; /* flow bfs initialize */
while (front < rear) { /* flow bfs loop */
int u =
queue[front++]; /* flow dequeue */
for (int v = 0; v < V; v++) { /* flow edge loop */
if (
!visited[v] &&
residual[u][v] > 0
) { /* flow residual check */
parent[v] = u;
visited[v] = 1;
queue[rear++] =
v; /* flow enqueue */
}
}
}
return visited[sink]; /* flow bfs result */
}
int main(void) {
int capacity[V][V] = {
{0, 16, 13, 0, 0, 0},
{0, 0, 10, 12, 0, 0},
{0, 4, 0, 0, 14, 0},
{0, 0, 9, 0, 0, 20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}
};
int residual[V][V];
int parent[V];
int maximum = 0;
for (int u = 0; u < V; u++) {
for (int v = 0; v < V; v++) {
residual[u][v] =
capacity[u][v]; /* flow initialize */
}
}
while (
bfs(
residual,
0,
5,
parent
)
) { /* flow augment loop */
int pathFlow = INT_MAX;
for (
int v = 5;
v != 0;
v = parent[v]
) { /* flow bottleneck loop */
int u = parent[v];
if (
residual[u][v] < pathFlow
) {
pathFlow =
residual[u][v]; /* flow bottleneck */
}
}
for (
int v = 5;
v != 0;
v = parent[v]
) { /* flow update loop */
int u = parent[v];
residual[u][v] -=
pathFlow; /* flow forward update */
residual[v][u] +=
pathFlow; /* flow reverse update */
}
maximum +=
pathFlow; /* flow total update */
}
printf(
"Maximum flow = %d\n",
maximum
); /* flow output */
return 0;
}
đŹ 7. Premium Advanced Graph Visualizer
Select an algorithm and follow vertex selection, edge inspection, relaxation, union, queue, stack, component and residual-flow updates.
Code
Bhavya
đ¸ď¸ Live Graph
đ 8. Program Tracing â Advanced Graphs
The complete selected C program appears with executable-line highlighting, live variables, graph state and automatic current-line scrolling.
PROGRAM TRACING â ADVANCED GRAPH ALGORITHMS
C Source Code
âąď¸ 9. Complexity Comparison
| Algorithm | Time | Space | Output |
|---|---|---|---|
| Prim | O(E log V) | O(V + E) | MST |
| Kruskal | O(E log E) | O(V + E) | MST |
| Dijkstra | O(E log V) | O(V + E) | Single-source distances |
| BellmanâFord | O(VE) | O(V) | Distances and negative cycle |
| FloydâWarshall | O(VÂł) | O(V²) | All-pairs distances |
| Kahn | O(V + E) | O(V) | Topological order or cycle |
| Kosaraju | O(V + E) | O(V + E) | SCC partition |
| EdmondsâKarp | O(VE²) | O(V²) | Maximum flow |
âď¸ 10. Practice Problems
1. How many edges does a spanning tree of V vertices contain?
2. Why does Kruskal require DSU?
3. Can Dijkstra process a negative edge safely?
4. Why are V â 1 BellmanâFord passes sufficient?
5. What FloydâWarshall value reveals a negative cycle?
6. When does Kahnâs algorithm report a cycle?
7. Why does Kosaraju transpose the graph?
8. What is an augmenting path?
9. What does a reverse residual edge permit?
10. Which MST cut property justifies a greedy choice?
đ 11. Quick Revision
- Prim grows one tree; Kruskal joins a forest using DSU.
- Dijkstra requires nonnegative weights.
- BellmanâFord supports negative edges and detects reachable negative cycles.
- FloydâWarshall solves all-pairs shortest paths in O(VÂł).
- Kahnâs algorithm uses indegrees and a zero-indegree queue.
- Kosaraju uses finish order, a transpose and a second DFS.
- Residual forward and reverse edges make flow decisions reversible.
- EdmondsâKarp uses BFS and runs in O(VE²).
- Relaxation comparisons and updates are traced separately.
- Repeated iterations return to their actual loop line.