Document 1
Document 1
Document 1
Given a directed graph and two vertices in it, source s and destination t, find out the maximum number of edge
disjoint paths from s to t. Two paths are said edge disjoint if they dont share any edge.
There can be maximum two edge disjoint paths from source 0 to destination 7 in the above graph. Two edge disjoint
paths are highlighted below in red and blue colors are 0-2-6-7 and 0-3-6-5-7.
Note that the paths may be different, but the maximum number is same. For example, in the above diagram, another
possible set of paths is 0-1-2-6-7 and 0-3-6-5-7 respectively.
This problem can be solved by reducing it to maximum flow problem. Following are steps.
1) Consider the given source and destination as source and sink in flow network. Assign unit capacity to each edge.
2) Run Ford-Fulkerson algorithm to find the maximum flow from source to sink.
3) The maximum flow is equal to the maximum number of edge-disjoint paths.
When we run Ford-Fulkerson, we reduce the capacity by a unit. Therefore, the edge can not be used again. So the
maximum flow is equal to the maximum number of edge-disjoint paths.
Following is C++ implementation of the above algorithm. Most of the code is taken from here.
// C++ program to find maximum number of edge disjoint paths
#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
// Number of vertices in given graph
#define V 8
/* Returns true if there is a path from source 's' to sink 't' in
int max_flow = 0;
{
// Find minimum residual capacity of the edges along the
// path filled by BFS. Or we can say find the maximum flow
// through the path found.
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
// update residual capacities of the edges and reverse edges
// along the path
for (v=t; v != s; v=parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
// Add path flow to overall flow
max_flow += path_flow;
}
// Return the overall flow (max_flow is equal to maximum
// number of edge-disjoint paths)
return max_flow;
}
// Driver program to test above functions
int main()
{
// Let us create a graph shown in the above example
int graph[V][V] = { {0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1, 0, 1},
{0, 0, 0, 0, 0, 0, 0, 0}
};
int s =
int t =
cout <<
<<
0;
7;
"There can be maximum " << findDisjointPaths(graph, s, t)
" edge-disjoint paths from " << s <<" to "<< t ;
return 0;
}
if (!visited[node.getV()])
topologicalSortUtil(node.getV(), visited, Stack);
}
// Push current vertex to stack which stores topological sort
Stack.push(v);
}
// The function to find longest distances from a given vertex. It uses
// recursive topologicalSortUtil() to get topological sorting.
void Graph::longestPath(int s)
{
stack<int> Stack;
int dist[V];
// Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to store Topological Sort
// starting from all vertices one by one
for (int i = 0; i < V; i++)
if (visited[i] == false)
topologicalSortUtil(i, visited, Stack);
// Initialize distances to all vertices as infinite and distance
// to source as 0
for (int i = 0; i < V; i++)
dist[i] = NINF;
dist[s] = 0;
// Process vertices in topological order
while (Stack.empty() == false)
{
// Get the next vertex from topological order
int u = Stack.top();
Stack.pop();
// Update distances of all adjacent vertices
list<AdjListNode>::iterator i;
if (dist[u] != NINF)
{
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (dist[i->getV()] < dist[u] + i->getWeight())
dist[i->getV()] = dist[u] + i->getWeight();
}
}
// Print the calculated longest distances
for (int i = 0; i < V; i++)
(dist[i] == NINF)? cout << "INF ": cout << dist[i] << " ";
}
// Driver program to test above functions
int main()
{
// Create a graph given in the above diagram.
while there are untried conflagrations { generate the next configuration if ( there are edges between two consecutive
vertices of this configuration and there is an edge from the last vertex to the first ). { print this configuration; break; } }
Backtracking Algorithm
Create an empty path array and add vertex 0 to it. Add other vertices, starting from the vertex 1. Before
adding a vertex, check for whether it is adjacent to the previously added vertex and not already added. If we
find such a vertex, we add the vertex as part of the solution. If we do not find a vertex then we return false.
Implementation of Backtracking solution
Following is C/C++ implementation of the Backtracking solution.
// Program to print Hamiltonian cycle
#include<stdio.h>
// Number of vertices in the graph
#define V 5
void printSolution(int path[]);
/* A utility function to check if the vertex v can be added at index 'pos'
in the Hamiltonian Cycle constructed so far (stored in 'path[]') */
bool isSafe(int v, bool graph[V][V], int path[], int pos)
{
/* Check if this vertex is an adjacent vertex of the previously
added vertex. */
if (graph [ path[pos-1] ][ v ] == 0)
return false;
/* Check if the vertex has already been included.
This step can be optimized by creating an array of size V */
for (int i = 0; i < pos; i++)
if (path[i] == v)
return false;
return true;
}
/* A recursive utility function to solve hamiltonian cycle problem */
bool hamCycleUtil(bool graph[V][V], int path[], int pos)
{
/* base case: If all vertices are included in Hamiltonian Cycle */
if (pos == V)
{
// And if there is an edge from the last included vertex to the
// first vertex
if ( graph[ path[pos-1] ][ path[0] ] == 1 )
return true;
else
return false;
}
// Try different vertices as a next candidate in Hamiltonian Cycle.
// We don't try for 0 as we included 0 as starting point in in hamCycle()
for (int v = 1; v < V; v++)
{
/* Check if this vertex can be added to Hamiltonian Cycle */
if (isSafe(v, graph, path, pos))
{
path[pos] = v;
/* recur to construct rest of the path */
if (hamCycleUtil (graph, path, pos+1) == true)
return true;
/* If adding vertex v doesn't lead to a solution,
then remove it */
path[pos] = -1;
}
}
/* If no vertex can be added to Hamiltonian Cycle constructed so far,
then return false */
return false;
}
/* This function solves the Hamiltonian Cycle problem using Backtracking.
It mainly uses hamCycleUtil() to solve the problem. It returns false
if there is no Hamiltonian Cycle possible, otherwise return true and
prints the path. Please note that there may be more than one solutions,
this function prints one of the feasible solutions. */
bool hamCycle(bool graph[V][V])
{
int *path = new int[V];
for (int i = 0; i < V; i++)
path[i] = -1;
/* Let us put vertex 0 as the first vertex in the path. If there is
a Hamiltonian Cycle, then the path can be started from any point
of the cycle as the graph is undirected */
path[0] = 0;
if ( hamCycleUtil(graph, path, 1) == false )
{
printf("\nSolution does not exist");
return false;
}
printSolution(path);
return true;
}
/* A utility function to print solution */
void printSolution(int path[])
{
printf ("Solution Exists:"
" Following is one Hamiltonian Cycle \n");
for (int i = 0; i < V; i++)
printf(" %d ", path[i]);
// Let us print the first vertex again to show the complete cycle
printf(" %d ", path[0]);
printf("\n");
}
// driver program to test above function
int main()
{
possible cases.
1) k is not an intermediate vertex in shortest path from i to j. We keep the value of dist[i][j] as it is.
2) k is an intermediate vertex in shortest path from i to j. We update the value of dist[i][j] as dist[i][k] + dist[k][j].
The following figure is taken from the Cormen book. It shows the above optimal substructure property in the all-pairs
shortest path problem.
for (j
{
//
//
if
= 0; j < V; j++)
If vertex k is on the shortest path from
i to j, then update the value of dist[i][j]
(dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// Print the shortest distance matrix
printSolution(dist);
}
/* A utility function to print solution */
void printSolution(int dist[][V])
{
printf ("Following matrix shows the shortest distances"
" between every pair of vertices \n");
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
if (dist[i][j] == INF)
printf("%7s", "INF");
else
printf ("%7d", dist[i][j]);
}
printf("\n");
}
}
// driver program to test above function
int main()
{
/* Let us create the following weighted graph
10
(0)------->(3)
|
/|\
5 |
|
|
| 1
\|/
|
(1)------->(2)
3
*/
int graph[V][V] = { {0,
5, INF, 10},
{INF, 0,
3, INF},
{INF, INF, 0,
1},
{INF, INF, INF, 0}
};
// Print the solution
floydWarshell(graph);
return 0;
}
A graph where all vertices are connected with each other, has exactly one connected component, consisting of the
whole graph. Such graph with only one connected component is called as Strongly Connected Graph.
The problem can be easily solved by applying DFS() on each component. In each DFS() call, a component or a subgraph is visited. We will call DFS on the next un-visited component. The number of calls to DFS() gives the number of
connected components. BFS can also be used.
What is an island?
A group of connected 1s forms an island. For example, the below matrix contains 5 islands
{1, 1, 0, 0, 0}, {0, 1, 0, 0, 1}, {1, 0, 0, 1, 1}, {0, 0, 0, 0, 0}, {1, 0, 1, 0, 1}
A cell in 2D matrix can be connected to 8 neighbors. So, unlike standard DFS(), where we recursively call for all
adjacent vertices, here we can recursive call for 8 neighbors only. We keep track of the visited 1s so that they are not
visited again.
// Program to count islands in boolean 2D matrix
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define ROW 5
#define COL 5
// A function to check if a given cell (row, col) can be included in DFS
int isSafe(int M[][COL], int row, int col, bool visited[][COL])
{
return (row >= 0) && (row < ROW) &&
// row number is in range
(col >= 0) && (col < COL) &&
// column number is in range
(M[row][col] && !visited[row][col]); // value is 1 and not yet visited
}
// A utility function to do DFS for a 2D boolean matrix. It only considers
// the 8 neighbors as adjacent vertices
void DFS(int M[][COL], int row, int col, bool visited[][COL])
{
// These arrays are used to get row and column numbers of 8 neighbors
// of a given cell
static int rowNbr[] = {-1, -1, -1, 0, 0, 1, 1, 1};
static int colNbr[] = {-1, 0, 1, -1, 1, -1, 0, 1};
{1, 1, 0, 0, 0},
1},
1},
0},
1}
Union(parent, x, y);
}
return 0;
}
// Driver program to test above functions
int main()
{
/* Let us create following graph
0
| \
|
\
1-----2 */
struct Graph* graph = createGraph(3, 3);
// add edge 0-1
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
// add edge 1-2
graph->edge[1].src = 1;
graph->edge[1].dest = 2;
// add edge 0-2
graph->edge[2].src = 0;
graph->edge[2].dest = 2;
if (isCycle(graph))
printf( "Graph contains cycle" );
else
printf( "Graph doesn't contain cycle" );
return 0;
}
int V = graph->V;
int E = graph->E;
// Allocate memory for creating V sets
struct subset *subsets =
(struct subset*) malloc( V * sizeof(struct subset) );
for (int v = 0; v < V; ++v)
{
subsets[v].parent = v;
subsets[v].rank = 0;
}
// Iterate through all edges of graph, find sets of both
// vertices of every edge, if sets are same, then there is
// cycle in graph.
for(int e = 0; e < E; ++e)
{
int x = find(subsets, graph->edge[e].src);
int y = find(subsets, graph->edge[e].dest);
if (x == y)
return 1;
Union(subsets, x, y);
}
return 0;
}
// Driver program to test above functions
int main()
{
/* Let us create following graph
0
| \
|
\
1-----2 */
int V = 3, E = 3;
struct Graph* graph = createGraph(V, E);
// add edge 0-1
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
// add edge 1-2
graph->edge[1].src = 1;
graph->edge[1].dest = 2;
// add edge 0-2
graph->edge[2].src = 0;
graph->edge[2].dest = 2;
if (isCycle(graph))
printf( "Graph contains cycle" );
else
printf( "Graph doesn't contain cycle" );
return 0;
}
The graph contains 9 vertices and 14 edges. So, the minimum spanning tree formed will be having (9 1) = 8 edges.
After sorting: Weight Src Dest 1 7 6 2 8 2 2 6 5 4 0 1 4 2 5 6 8 6 7 2 3 7 7 8 8 0 7 8 1 2 9 3 4 10 5 4 11 1 7 14 3 5
Now pick all edges one by one from sorted list of edges
1. Pick edge 7-6: No cycle is formed, include it.
6. Pick edge 8-6: Since including this edge results in cycle, discard it.
7. Pick edge 2-3: No cycle is formed, include it.
8. Pick edge 7-8: Since including this edge results in cycle, discard it.
10. Pick edge 1-2: Since including this edge results in cycle, discard it.
11. Pick edge 3-4: No cycle is formed, include it.
Since the number of edges included equals (V 1), the algorithm stops here.
// Kruskal's algortihm to find Minimum Spanning Tree of a given connected,
// undirected and weighted graph
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// a structure to represent a weighted edge in graph
struct Edge
{
int src, dest, weight;
};
// a structure to represent a connected, undirected and weighted graph
struct Graph
{
// V-> Number of vertices, E-> Number of edges
int V, E;
// graph is represented as an array of edges. Since the graph is
// undirected, the edge from src to dest is also edge from dest
// to src. Both are counted as 1 edge here.
struct Edge* edge;
};
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
graph->V = V;
graph->E = E;
graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
return graph;
}
// A structure to represent a subset for union-find
struct subset
{
int parent;
int rank;
};
// A utility function to find set of an element i
// (uses path compression technique)
int find(struct subset subsets[], int i)
{
// find root and make root as parent of i (path compression)
if (subsets[i].parent != i)
subsets[i].parent = find(subsets, subsets[i].parent);
return subsets[i].parent;
}
// A function that does union of two sets of x and y
// (uses union by rank)
void Union(struct subset subsets[], int x, int y)
{
int xroot = find(subsets, x);
int yroot = find(subsets, y);
// Attach smaller rank tree under root of high rank tree
// (Union by Rank)
if (subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
// If ranks are same, then make one as root and increment
// its rank by one
else
{
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}
// Compare two edges according to their weights.
// Used in qsort() for sorting an array of edges
int myComp(const void* a, const void* b)
{
struct Edge* a1 = (struct Edge*)a;
struct Edge* b1 = (struct Edge*)b;
return a1->weight > b1->weight;
}
// The main function to construct MST using Kruskal's algorithm
void KruskalMST(struct Graph* graph)
{
int V = graph->V;
struct Edge result[V]; // Tnis will store the resultant MST
int e = 0; // An index variable, used for result[]
int i = 0;
The set mstSet is initially empty and keys assigned to vertices are {0, INF, INF, INF, INF, INF, INF, INF} where INF
indicates infinite. Now pick the vertex with minimum key value. The vertex 0 is picked, include it in mstSet. So mstSet
becomes {0}. After including to mstSet, update key values of adjacent vertices. Adjacent vertices of 0 are 1 and 7.
The key values of 1 and 7 are updated as 4 and 8. Following subgraph shows vertices and their key values, only the
vertices with finite key values are shown. The vertices included in MST are shown in green color.
Pick the vertex with minimum key value and not already included in MST (not in mstSET). The vertex 1 is picked and
added to mstSet. So mstSet now becomes {0, 1}. Update the key values of adjacent vertices of 1. The key value of
vertex 2 becomes 8.
Pick the vertex with minimum key value and not already included in MST (not in mstSET). We can either pick vertex 7
or vertex 2, let vertex 7 is picked. So mstSet now becomes {0, 1, 7}. Update the key values of adjacent vertices of 7.
Pick the vertex with minimum key value and not already included in MST (not in mstSET). Vertex 6 is picked. So
mstSet now becomes {0, 1, 7, 6}. Update the key values of adjacent vertices of 6. The key value of vertex 5 and 8 are
updated.
We repeat the above steps until mstSet includes all vertices of given graph. Finally, we get the following graph.
minimum weight edge from the cut. Min Heap is used as time complexity of operations like extracting minimum
element and decreasing key value is O(LogV) in Min Heap.
Following are the detailed steps.
1) Create a Min Heap of size V where V is the number of vertices in the given graph. Every node of min heap
contains vertex number and key value of the vertex.
2) Initialize Min Heap with first vertex as root (the key value assigned to first vertex is 0). The key value assigned to
all other vertices is INF (infinite).
3) While Min Heap is not empty, do following
..a) Extract the min value node from Min Heap. Let the extracted vertex be u.
..b) For every adjacent vertex v of u, check if v is in Min Heap (not yet included in MST). If v is in Min Heap and its
key value is more than weight of u-v, then update the key value of v as weight of u-v.
Let us understand the above algorithm with the following example:
Initially, key value of first vertex is 0 and INF (infinite) for all other vertices. So vertex 0 is extracted from Min Heap
and key values of vertices adjacent to 0 (1 and 7) are updated. Min Heap contains all vertices except vertex 0.
The vertices in green color are the vertices included in MST.
Since key value of vertex 1 is minimum among all nodes in Min Heap, it is extracted from Min Heap and key values of
vertices adjacent to 1 are updated (Key is updated if the a vertex is not in Min Heap and previous key value is greater
than the weight of edge from 1 to the adjacent). Min Heap contains all vertices except vertex 0 and 1.
Since key value of vertex 7 is minimum among all nodes in Min Heap, it is extracted from Min Heap and key values of
vertices adjacent to 7 are updated (Key is updated if the a vertex is not in Min Heap and previous key value is greater
than the weight of edge from 7 to the adjacent). Min Heap contains all vertices except vertex 0, 1 and 7.
Since key value of vertex 6 is minimum among all nodes in Min Heap, it is extracted from Min Heap and key values of
vertices adjacent to 6 are updated (Key is updated if the a vertex is not in Min Heap and previous key value is greater
than the weight of edge from 6 to the adjacent). Min Heap contains all vertices except vertex 0, 1, 7 and 6.
The above steps are repeated for rest of the nodes in Min Heap till Min Heap becomes empty
// C / C++ program for Prim's MST for adjacency list representation of graph
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// A structure to represent a node in adjacency list
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
// A structure to represent an adjacency liat
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
minHeap->pos[smallestNode->v] = idx;
minHeap->pos[idxNode->v] = smallest;
// Swap nodes
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
return minHeap->size == 0;
}
// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
if (isEmpty(minHeap))
return NULL;
// Store the root node
struct MinHeapNode* root = minHeap->array[0];
// Replace root node with last node
struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
minHeap->array[0] = lastNode;
// Update position of last node
minHeap->pos[root->v] = minHeap->size-1;
minHeap->pos[lastNode->v] = 0;
// Reduce heap size and heapify root
--minHeap->size;
minHeapify(minHeap, 0);
return root;
}
// Function to decreasy key value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int key)
{
// Get the index of v in heap array
int i = minHeap->pos[v];
// Get the node and update its key value
minHeap->array[i]->key = key;
// Travel up while the complete tree is not hepified.
// This is a O(Logn) loop
while (i && minHeap->array[i]->key < minHeap->array[(i - 1) / 2]->key)
{
// Swap this node with its parent
minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);
}
pCrawl = pCrawl->next;
}
}
// print edges of MST
printArr(parent, V);
}
// Driver program to test above functions
int main()
{
// Let us create the graph given in above fugure
int V = 9;
struct Graph* graph = createGraph(V);
addEdge(graph, 0, 1, 4);
addEdge(graph, 0, 7, 8);
addEdge(graph, 1, 2, 8);
addEdge(graph, 1, 7, 11);
addEdge(graph, 2, 3, 7);
addEdge(graph, 2, 8, 2);
addEdge(graph, 2, 5, 4);
addEdge(graph, 3, 4, 9);
addEdge(graph, 3, 5, 14);
addEdge(graph, 4, 5, 10);
addEdge(graph, 5, 6, 2);
addEdge(graph, 6, 7, 1);
addEdge(graph, 6, 8, 6);
addEdge(graph, 7, 8, 7);
PrimMST(graph);
return 0;
}
Run on IDE
Output:
0-15-22-33-46-57-60-72-8
Time Complexity: The time complexity of the above code/algorithm looks O(V^2) as there are two nested while
loops. If we take a closer look, we can observe that the statements in inner loop are executed O(V+E) times (similar
to BFS). The inner loop has decreaseKey() operation which takes O(LogV) time. So overall time complexity is
O(E+V)*O(LogV) which is O((E+V)*LogV) = O(ELogV) (For a connected graph, V = O(E))
Initially, distance value of source vertex is 0 and INF (infinite) for all other vertices. So source vertex is extracted from
Min Heap and distance values of vertices adjacent to 0 (1 and 7) are updated. Min Heap contains all vertices except
vertex 0.
The vertices in green color are the vertices for which minimum distances are finalized and are not in Min Heap
Since distance value of vertex 1 is minimum among all nodes in Min Heap, it is extracted from Min Heap and distance
values of vertices adjacent to 1 are updated (distance is updated if the a vertex is not in Min Heap and distance
through 1 is shorter than the previous distance). Min Heap contains all vertices except vertex 0 and 1.
Pick the vertex with minimum distance value from min heap. Vertex 7 is picked. So min heap now contains all
vertices except 0, 1 and 7. Update the distance values of adjacent vertices of 7. The distance value of vertex 6 and 8
becomes finite (15 and 9 respectively).
Pick the vertex with minimum distance from min heap. Vertex 6 is picked. So min heap now contains all vertices
except 0, 1, 7 and 6. Update the distance values of adjacent vertices of 6. The distance value of vertex 5 and 8 are
updated.
Above steps are repeated till min heap doesnt become empty. Finally, we get the following shortest path tree.
return minHeap;
}
// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
int smallest, left, right;
smallest = idx;
left = 2 * idx + 1;
right = 2 * idx + 2;
if (left < minHeap->size &&
minHeap->array[left]->dist < minHeap->array[smallest]->dist )
smallest = left;
if (right < minHeap->size &&
minHeap->array[right]->dist < minHeap->array[smallest]->dist )
smallest = right;
if (smallest != idx)
{
// The nodes to be swapped in min heap
MinHeapNode *smallestNode = minHeap->array[smallest];
MinHeapNode *idxNode = minHeap->array[idx];
// Swap positions
minHeap->pos[smallestNode->v] = idx;
minHeap->pos[idxNode->v] = smallest;
// Swap nodes
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
return minHeap->size == 0;
}
// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
if (isEmpty(minHeap))
return NULL;
// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
void dijkstra(struct Graph* graph, int src)
{
int V = graph->V;// Get the number of vertices in graph
int dist[V];
// dist values used to pick minimum weight edge in cut
// minHeap represents set E
struct MinHeap* minHeap = createMinHeap(V);
// Initialize min heap with all vertices. dist value of all vertices
for (int v = 0; v < V; ++v)
{
dist[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v, dist[v]);
minHeap->pos[v] = v;
}
// Make dist value of src vertex as 0 so that it is extracted first
minHeap->array[src] = newMinHeapNode(src, dist[src]);
minHeap->pos[src]
= src;
dist[src] = 0;
decreaseKey(minHeap, src, dist[src]);
// Initially size of min heap is equal to V
minHeap->size = V;
// In the followin loop, min heap contains all nodes
// whose shortest distance is not yet finalized.
while (!isEmpty(minHeap))
{
// Extract the vertex with minimum distance value
struct MinHeapNode* minHeapNode = extractMin(minHeap);
int u = minHeapNode->v; // Store the extracted vertex number
// Traverse through all adjacent vertices of u (the extracted
// vertex) and update their distance values
struct AdjListNode* pCrawl = graph->array[u].head;
while (pCrawl != NULL)
{
int v = pCrawl->dest;
// If shortest distance to v is not finalized yet, and distance to v
// through u is less than its previously calculated distance
if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
pCrawl->weight + dist[u] < dist[v])
{
dist[v] = dist[u] + pCrawl->weight;
// update distance value in min heap also
decreaseKey(minHeap, v, dist[v]);
}
pCrawl = pCrawl->next;
}
}
// print the calculated shortest distances
printArr(dist, V);
}
Let all edges are processed in following order: (B,E), (D,B), (B,D), (A,B), (A,C), (D,C), (B,C), (E,D). We get following
distances when all edges are processed first time. The first row in shows initial distances. The second row shows
distances when edges (B,E), (D,B), (B,D) and (A,B) are processed. The third row shows distances when (A,C) is
processed. The fourth row shows when (D,C), (B,C) and (E,D) are processed.
The first iteration guarantees to give all shortest paths which are at most 1 edge long. We get following distances
when all edges are processed second time (The last row shows final values).
The second iteration guarantees to give all shortest paths which are at most 2 edges long. The algorithm processes
all edges 2 more times. The distances are minimized after the second iteration, so third and fourth iterations dont
update the distances.
Implementation:
// A C / C++ program for Bellman-Ford's single source shortest path algorithm.
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<string.h>
<limits.h>
};
// a structure to represent a connected, directed and weighted graph
struct Graph
{
// V-> Number of vertices, E-> Number of edges
int V, E;
// graph is represented as an array of edges.
struct Edge* edge;
};
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
graph->V = V;
graph->E = E;
graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
return graph;
}
// A utility function used to print the solution
void printArr(int dist[], int n)
{
printf("Vertex
Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
// The main function that finds shortest distances from src to all other
// vertices using Bellman-Ford algorithm. The function also detects negative
// weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
// Step 1: Initialize distances from src to all other vertices as INFINITE
for (int i = 0; i < V; i++)
dist[i]
= INT_MAX;
dist[src] = 0;
// Step 2: Relax all edges |V| - 1 times. A simple shortest path from src
// to any other vertex can have at-most |V| - 1 edges
for (int i = 1; i <= V-1; i++)
{
for (int j = 0; j < E; j++)
{
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
// Step 3: check for negative-weight cycles. The above step guarantees
// shortest distances if graph doesn't contain negative weight cycle.
// If we get a shorter path, then there is a cycle.
for (int i = 0; i < E; i++)
{
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
printf("Graph contains negative weight cycle");
}
printArr(dist, V);
return;
}
// Driver program to test above functions
int main()
{
/* Let us create the graph given in above example */
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V, E);
// add edge 0-1 (or A-B in above figure)
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;
// add edge 0-2 (or A-C in above figure)
graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;
// add edge 1-2 (or B-C in above figure)
graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;
// add edge 1-3 (or B-D in above figure)
graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;
// add edge 1-4 (or A-E in above figure)
graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;
// add edge 3-2 (or D-C in above figure)
graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;
// add edge 3-1 (or D-B in above figure)
graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;
// add edge 4-3 (or E-D in above figure)
graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;
BellmanFord(graph, 0);
return 0;
}
Run on IDE
Output:
Vertex Distance from Source 0 0 1 -1 2 2 3 -2 4 1
Notes
1) Negative weights are found in various applications of graphs. For example, instead of paying cost for a path, we
may get some advantage if we follow the path.
2) Bellman-Ford works better (better than Dijksras) for distributed systems. Unlike Dijksras where we need to find
minimum value of all vertices, in Bellman-Ford, edges are considered one by one.
Exercise
1) The standard Bellman-Ford algorithm reports shortest path only if there is no negative weight cycles. Modify it so
that it reports minimum distances even if there is a negative weight cycle.
2) Can we use Dijksras algorithm for shortest paths for graphs with negative weights one idea can be, calculate the
minimum weight value, add a positive value (equal to absolute value of minimum weight value) to all weights and run
the Dijksras algorithm for the modified graph. Will this algorithm work?
2) Instead of using arithmetic operations, we can use logical operations. For arithmetic operation +, logical and &&
is used, and for min, logical or || is used. (We save time by a constant factor. Time complexity is same though)
// Program for transitive closure using Floyd Warshall Algorithm
#include<stdio.h>
// Number of vertices in the graph
#define V 4
// A function to print the solution matrix
void printSolution(int reach[][V]);
// Prints transitive closure of graph[][] using Floyd Warshall algorithm
void transitiveClosure(int graph[][V])
{
/* reach[][] will be the output matrix that will finally have the shortest
distances between every pair of vertices */
int reach[V][V], i, j, k;
/* Initialize the solution matrix same as input graph matrix. Or
we can say the initial values of shortest distances are based
on shortest paths considering no intermediate vertex. */
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
reach[i][j] = graph[i][j];
/* Add all vertices one by one to the set of intermediate vertices.
---> Before start of a iteration, we have reachability values for all
pairs of vertices such that the reachability values consider only the
vertices in set {0, 1, 2, .. k-1} as intermediate vertices.
----> After the end of a iteration, vertex no. k is added to the set of
intermediate vertices and the set becomes {0, 1, 2, .. k} */
for (k = 0; k < V; k++)
{
// Pick all vertices as source one by one
for (i = 0; i < V; i++)
{
// Pick all vertices as destination for the
// above picked source
for (j = 0; j < V; j++)
{
// If vertex k is on a path from i to j,
// then make sure that the value of reach[i][j] is 1
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
}
}
}
// Print the shortest distance matrix
printSolution(reach);
}
/* A utility function to print solution */
void printSolution(int reach[][V])
{
printf ("Following matrix is transitive closure of the given graph\n");
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
A bipartite graph is possible if the graph coloring is possible using two colors such that vertices in a set are colored
with the same color. Note that it is possible to color a cycle graph with even cycle using two colors. For example, see
the following graph.
It is not possible to color a cycle graph with odd cycle using two colors.
{
// Create a color array to store colors assigned to all veritces. Vertex
// number is used as index in this array. The value '-1' of colorArr[i]
// is used to indicate that no color is assigned to vertex 'i'. The value
// 1 is used to indicate first color is assigned and value 0 indicates
// second color is assigned.
int colorArr[V];
for (int i = 0; i < V; ++i)
colorArr[i] = -1;
// Assign first color to source
colorArr[src] = 1;
// Create a queue (FIFO) of vertex numbers and enqueue source vertex
// for BFS traversal
queue <int> q;
q.push(src);
// Run while there are vertices in queue (Similar to BFS)
while (!q.empty())
{
// Dequeue a vertex from queue ( Refer http://goo.gl/35oz8 )
int u = q.front();
q.pop();
// Find all non-colored adjacent vertices
for (int v = 0; v < V; ++v)
{
// An edge from u to v exists and destination v is not colored
if (G[u][v] && colorArr[v] == -1)
{
// Assign alternate color to this adjacent v of u
colorArr[v] = 1 - colorArr[u];
q.push(v);
}
// An edge from u to v exists and destination v is colored with
// same color as u
else if (G[u][v] && colorArr[v] == colorArr[u])
return false;
}
}
// If we reach here, then all adjacent vertices can be colored with
// alternate color
return true;
}
// Driver program to test above function
int main()
{
int G[][V] = {{0, 1, 0, 1},
{1, 0, 1, 0},
{0, 1, 0, 1},
{1, 0, 1, 0}
};
isBipartite(G, 0) ? cout << "Yes" : cout << "No";
return 0;
}
Run on IDE
Output:
Yes
Refer this for C implementation of the same.
Time Complexity of the above approach is same as that Breadth First Search. In above implementation is O(V^2)
where V is number of vertices. If graph is represented using adjacency list, then the complexity becomes O(V+E).
Topological Sorting
Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge
uv, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG.
For example, a topological sorting of the following graph is 5 4 2 3 1 0. There can be more than one topological
sorting for a graph. For example, another topological sorting of the following graph is 4 5 2 3 1 0. The first vertex in
topological sorting is always a vertex with in-degree as 0 (a vertex with no in-coming edges).
int s = 1;
cout << "Following are shortest distances from source " << s <<" \n";
g.shortestPath(s);
return 0;
}
We can find all strongly connected components in O(V+E) time using Kosarajus algorithm. Following is detailed
Kosarajus algorithm.
1) Create an empty stack S and do DFS traversal of a graph. In DFS traversal, after calling recursive DFS for
adjacent vertices of a vertex, push the vertex to stack.
2) Reverse directions of all arcs to obtain the transpose graph.
3) One by one pop a vertex from S while S is not empty. Let the popped vertex be v. Take v as source and do DFS
(call DFSUtil(v)). The DFS starting from v prints strongly connected component of v.
How does this work?
The above algorithm is DFS based. It does DFS two times. DFS of a graph produces a single tree if all
vertices are reachable from the DFS starting point. Otherwise DFS produces a forest. So DFS of a graph with
only one SCC always produces a tree. The important point to note is DFS may produce a tree or a forest
when there are more than one SCCs depending upon the chosen starting point. For example, in the above
diagram, if we start DFS from vertices 0 or 1 or 2, we get a tree as output. And if we start from 3 or 4, we get a
forest. To find and print all SCCs, we would want to start DFS from vertex 4 (which is a sink vertex), then
move to 3 which is sink in the remaining set (set excluding 4) and finally any of the remaining vertices (0, 1,
2). So how do we find this sequence of picking vertices as starting points of DFS? Unfortunately, there is no
direct way for getting this sequence. However, if we do a DFS of graph and store vertices according to their
finish times, we make sure that the finish time of a vertex that connects to other SCCs (other that its own
SCC), will always be greater than finish time of vertices in the other SCC (See this for proof). For example, in
DFS of above example graph, finish time of 0 is always greater than 3 and 4 (irrespective of the sequence of vertices
considered for DFS). And finish time of 3 is always greater than 4. DFS doesnt guarantee about other vertices, for
example finish times of 1 and 2 may be smaller or greater than 3 and 4 depending upon the sequence of vertices
considered for DFS. So to use this property, we do DFS traversal of complete graph and push every finished vertex
to a stack. In stack, 3 always appears after 4, and 0 appear after both 3 and 4.
In the next step, we reverse the graph. Consider the graph of SCCs. In the reversed graph, the edges that
connect two components are reversed. So the SCC {0, 1, 2} becomes sink and the SCC {4} becomes source.
As discussed above, in stack, we always have 0 before 3 and 4. So if we do a DFS of the reversed graph
using sequence of vertices in stack, we process vertices from sink to source. That is what we wanted to
We do DFS traversal of given graph with additional code to find out Articulation Points (APs). In DFS traversal, we
maintain a parent[] array where parent[u] stores parent of vertex u. Among the above mentioned two cases, the first
case is simple to detect. For every vertex, count children. If currently visited vertex u is root (parent[u] is NIL) and has
more than two children, print it.
How to handle second case? The second case is trickier. We maintain an array disc[] to store discovery time of
vertices. For every node u, we need to find out the earliest visited vertex (the vertex with minimum discovery time)
that can be reached from subtree rooted with u. So we maintain an additional array low[] which is defined as follows.
low[u] = min(disc[u], disc[w]) where w is an ancestor of u and there is a back edge from some descendant of u to w.
Following is C++ implementation of Tarjans algorithm for finding articulation points.
// A C++ program to find articulation points in a given undirected graph
#include<iostream>
#include <list>
#define NIL -1
using namespace std;
// A class that represents an undirected graph
class Graph
{
int V;
// No. of vertices
list<int> *adj;
// A dynamic array of adjacency lists
void APUtil(int v, bool visited[], int disc[], int low[],
int parent[], bool ap[]);
public:
Graph(int V);
// Constructor
void addEdge(int v, int w);
// function to add an edge to graph
void AP();
// prints articulation points
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v); // Note: the graph is undirected
}
// A recursive function that find articulation points using DFS traversal
// u --> The vertex to be visited next
// visited[] --> keeps tract of visited vertices
// disc[] --> Stores discovery times of visited vertices
// parent[] --> Stores parent vertices in DFS tree
// ap[] --> Store articulation points
void Graph::APUtil(int u, bool visited[], int disc[],
int low[], int parent[], bool ap[])
{
// A static variable is used for simplicity, we can avoid use of static
// variable by passing a pointer.
static int time = 0;
// Count of children in DFS Tree
int children = 0;
// Mark the current node as visited
visited[u] = true;
// Initialize discovery time and low value
disc[u] = low[u] = ++time;
// Go through all vertices aadjacent to this
list<int>::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
int v = *i; // v is current adjacent of u
// If v is not visited yet, then make it a child of u
// in DFS tree and recur for it
if (!visited[v])
{
children++;
parent[v] = u;
APUtil(v, visited, disc, low, parent, ap);
// Check if the subtree rooted with v has a connection to
// one of the ancestors of u
low[u] = min(low[u], low[v]);
// u is an articulation point in following cases
// (1) u is root of DFS tree and has two or more chilren.
if (parent[u] == NIL && children > 1)
ap[u] = true;
// (2) If u is not root and low value of one of its child is more
// than discovery value of u.
if (parent[u] != NIL && low[v] >= disc[u])
ap[u] = true;
}
// Update low value of u for parent function calls.
else if (v != parent[u])
low[u] = min(low[u], disc[v]);
}
}
// The function to do DFS traversal. It uses recursive function APUtil()
void Graph::AP()
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
int *disc = new int[V];
int *low = new int[V];
int *parent = new int[V];
bool *ap = new bool[V]; // To store articulation points
// Initialize parent and visited, and ap(articulation point) arrays
for (int i = 0; i < V; i++)
{
parent[i] = NIL;
visited[i] = false;
ap[i] = false;
}
// Call the recursive helper function to find articulation points
// in DFS tree rooted with vertex 'i'
for (int i = 0; i < V; i++)
if (visited[i] == false)
APUtil(i, visited, disc, low, parent, ap);
// Now ap[] contains articulation points, print them
for (int i = 0; i < V; i++)
if (ap[i] == true)
cout << i << " ";
}
// Driver program to test above function
int main()
{
// Create graphs given in above diagrams
cout << "\nArticulation points in first graph \n";
Graph g1(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.AP();
cout << "\nArticulation points in second graph \n";
Graph g2(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
g2.AP();
cout << "\nArticulation points in third graph \n";
Graph g3(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
g3.AP();
return 0;
}
Bridges in a graph
An edge in an undirected connected graph is a bridge iff removing it disconnects the graph. For a disconnected
undirected graph, definition is similar, a bridge is an edge removing which increases number of connected
components.
Like Articulation Points,bridges represent vulnerabilities in a connected network and are useful for designing reliable
networks. For example, in a wired computer network, an articulation point indicates the critical computers and a
bridge indicates the critical wires or connections.
Following are some example graphs with bridges highlighted with red color.
an edge (u, v) (u is parent of v in DFS tree) is bridge if there does not exit any other alternative to reach u or an
ancestor of u from subtree rooted with v. As discussed in theprevious post, the value low[v] indicates earliest visited
vertex reachable from subtree rooted with v. The condition for an edge (u, v) to be a bridge is, low[v] > disc[u].
Following is C++ implementation of above approach.
// A C++ program to find bridges in a given undirected graph
#include<iostream>
#include <list>
#define NIL -1
using namespace std;
// A class that represents an undirected graph
class Graph
{
int V;
// No. of vertices
list<int> *adj;
// A dynamic array of adjacency lists
void bridgeUtil(int v, bool visited[], int disc[], int low[], int parent[]);
public:
Graph(int V);
// Constructor
void addEdge(int v, int w);
// function to add an edge to graph
void bridge();
// prints all bridges
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v); // Note: the graph is undirected
}
// A recursive function that finds and prints bridges using DFS traversal
// u --> The vertex to be visited next
// visited[] --> keeps tract of visited vertices
// disc[] --> Stores discovery times of visited vertices
// parent[] --> Stores parent vertices in DFS tree
void Graph::bridgeUtil(int u, bool visited[], int disc[],
int low[], int parent[])
{
// A static variable is used for simplicity, we can avoid use of static
// variable by passing a pointer.
static int time = 0;
// Mark the current node as visited
visited[u] = true;
// Initialize discovery time and low value
disc[u] = low[u] = ++time;
// Go through all vertices aadjacent to this
list<int>::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
int v = *i;
// v is current adjacent of u
Biconnected graph
An undirected graph is called Biconnected if there are two vertex-disjoint paths between any two vertices. In a
Biconnected Graph, there is a simple cycle through any two vertices.
By convention, two nodes connected by an edge form a biconnected graph, but this does not verify the above
properties. For a graph with more than two vertices, the above properties must be there for it to be Biconnected.
Following are some examples.
It is easy for undirected graph, we can just do a BFS and DFS starting from any vertex. If BFS or DFS visits all
vertices, then the given undirected graph is connected. This approach wont work for a directed graph. For example,
consider the following graph which is not strongly connected. If we start DFS (or BFS) from vertex 0, we can reach all
vertices, but if we start from any other vertex, we cannot reach all vertices.
Following are some interesting properties of undirected graphs with an Eulerian path and cycle. We can use these
properties to find whether a graph is Eulerian or not.
Eulerian Cycle
An undirected graph has Eulerian cycle if following two conditions are true.
.a) All vertices with non-zero degree are connected. We dont care about vertices with zero degree because
they dont belong to Eulerian Cycle or Path (we only consider all edges).
.b) All vertices have even degree.
Eulerian Path
An undirected graph has Eulerian Path if following two conditions are true.
.a) Same as condition (a) for Eulerian Cycle
.b) If zero or two vertices have odd degree and all other vertices have even degree. Note that only one
vertex with odd degree is not possible in an undirected graph (sum of all degrees is always even in an
undirected graph)
Note that a graph with no edges is considered Eulerian because there are no edges to traverse.
How does this work?
In Eulerian path, each time we visit a vertex v, we walk through two unvisited edges with one end point as v.
Therefore, all middle vertices in Eulerian Path must have even degree. For Eulerian Cycle, any vertex can be
middle vertex, therefore all vertices must have even degree.
// A C++ program to check if a given graph is Eulerian or not
#include<iostream>
#include <list>
using namespace std;
// A class that represents an undirected graph
class Graph
{
int V;
// No. of vertices
list<int> *adj;
// A dynamic array of adjacency lists
public:
// Constructor and destructor
Graph(int V)
{this->V = V; adj = new list<int>[V]; }
~Graph() { delete [] adj; } // To avoid memory leak
// function to add an edge to graph
void addEdge(int v, int w);
// Method to check if this graph is Eulerian or not
int isEulerian();
// Method to check if all non-zero degree vertices are connected
bool isConnected();
// Function to do DFS starting from v. Used in isConnected();
void DFSUtil(int v, bool visited[]);
};
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v); // Note: the graph is undirected
}
0);
2);
1);
3);
4);
0);
Graph g3(5);
g3.addEdge(1,
g3.addEdge(0,
g3.addEdge(2,
g3.addEdge(0,
g3.addEdge(3,
g3.addEdge(1,
test(g3);
0);
2);
1);
3);
4);
3);
The idea is to browse through all paths of length k from u to v using the approach discussed in theprevious post and
return weight of the shortest path. A simple solution is to start from u, go to all adjacent vertices and recur for
adjacent vertices with k as k-1, source as adjacent vertex and destination as v. Following is C++ implementation of
this simple solution.
// C++ program to find shortest path with exactly k edges
#include <iostream>
#include <climits>
using namespace std;
// Define number of vertices in the graph and inifinite value
#define V 4
#define INF INT_MAX
// A naive recursive function to count walks from u to v with k edges
int shortestPath(int graph[][V], int u, int v, int k)
{
// Base cases
if (k == 0 && u == v)
return 0;
if (k == 1 && graph[u][v] != INF) return graph[u][v];
if (k <= 0)
return INF;
// Initialize result
int res = INF;
// Go to all adjacents of u and recur
for (int i = 0; i < V; i++)
{
if (graph[u][i] != INF && u != i && v != i)
{
int rec_res = shortestPath(graph, i, v, k-1);
if (rec_res != INF)
res = min(res, graph[u][i] + rec_res);
}
}
return res;
}
// driver program to test above function
int main()
{
/* Let us create the graph shown in above diagram*/
int graph[V][V] = { {0, 10, 3, 2},
{INF, 0, INF, 7},
{INF, INF, 0, 6},
{INF, INF, INF, 0}
};
int u = 0, v = 3, k = 2;
cout << "Weight of the shortest path is " <<
shortestPath(graph, u, v, k);
return 0;
}
Run on IDE
Output:
Weight of the shortest path is 9
The worst case time complexity of the above function is O(Vk) where V is the number of vertices in the given graph.
We can simply analyze the time complexity by drawing recursion tree. The worst occurs for a complete graph. In
worst case, every internal node of recursion tree would have exactly V children.
We can optimize the above solution using Dynamic Programming. The idea is to build a 3D table where first
dimension is source, second dimension is destination, third dimension is number of edges from source to destination,
and the value is count of walks. Like other Dynamic Programming problems, we fill the 3D table in bottom up manner.
// Dynamic Programming based C++ program to find shortest path with
// exactly k edges
#include <iostream>
#include <climits>
using namespace std;
// Define number of vertices in the graph and inifinite value
#define V 4
#define INF INT_MAX
// A Dynamic programming based function to find the shortest path from
// u to v with exactly k edges.
int shortestPath(int graph[][V], int u, int v, int k)
{
// Table to be filled up using DP. The value sp[i][j][e] will store
// weight of the shortest path from i to j with exactly k edges
int sp[V][V][k+1];
// Loop for number of edges from 0 to k
for (int e = 0; e <= k; e++)
{
for (int i = 0; i < V; i++) // for source
{
for (int j = 0; j < V; j++) // for destination
{
// initialize value
sp[i][j][e] = INF;
// from base cases
if (e == 0 && i == j)
sp[i][j][e] = 0;
if (e == 1 && graph[i][j] != INF)
sp[i][j][e] = graph[i][j];
//go to adjacent only when number of edges is more than 1
if (e > 1)
{
for (int a = 0; a < V; a++)
{
// There should be an edge from i to a and a
// should not be same as either i or j
if (graph[i][a] != INF && i != a &&
j!= a && sp[a][j][e-1] != INF)
sp[i][j][e] = min(sp[i][j][e], graph[i][a] +
sp[a][j][e-1]);
}
}
}
}
}
return sp[u][v][k];
}
// driver program to test above function
int main()
{
/* Let us create the graph shown in above diagram*/
int graph[V][V] = { {0, 10, 3, 2},
{INF, 0, INF, 7},
{INF, INF, 0, 6},
{INF, INF, INF, 0}
};
int u = 0, v = 3, k = 2;
cout << shortestPath(graph, u, v, k);
return 0;
}
Run on IDE
Output:
Weight of the shortest path is 9
Time complexity of the above DP based solution is O(V 3K) which is much better than the naive solution.
#include <list>
#define CHARS 26
using namespace std;
// A class that represents an undirected graph
class Graph
{
int V;
// No. of vertices
list<int> *adj;
// A dynamic array of adjacency lists
int *in;
public:
// Constructor and destructor
Graph(int V);
~Graph()
{ delete [] adj; delete [] in; }
// function to add an edge to graph
void addEdge(int v, int w) { adj[v].push_back(w);
(in[w])++; }
Stack.push(v);
}
// The function to do Topological Sort. It uses recursive topologicalSortUtil()
void Graph::topologicalSort()
{
stack<int> Stack;
// Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to store Topological Sort
// starting from all vertices one by one
for (int i = 0; i < V; i++)
if (visited[i] == false)
topologicalSortUtil(i, visited, Stack);
// Print contents of stack
while (Stack.empty() == false)
{
cout << (char) ('a' + Stack.top()) << " ";
Stack.pop();
}
}
int min(int x, int y)
{
return (x < y)? x : y;
}
// This function fidns and prints order of characer from a sorted
// array of words. n is size of words[]. alpha is set of possible
// alphabets.
// For simplicity, this function is written in a way that only
// first 'alpha' characters can be there in words array. For
// example if alpha is 7, then words[] should have only 'a', 'b',
// 'c' 'd', 'e', 'f', 'g'
void printOrder(string words[], int n, int alpha)
{
// Create a graph with 'aplha' edges
Graph g(alpha);
// Process all adjacent pairs of words and create a graph
for (int i = 0; i < n-1; i++)
{
// Take the current two words and find the first mismatching
// character
string word1 = words[i], word2 = words[i+1];
for (int j = 0; j < min(word1.length(), word2.length()); j++)
{
// If we find a mismatching character, then add an edge
// from character of word1 to that of word2
if (word1[j] != word2[j])
{
g.addEdge(word1[j]-'a', word2[j]-'a');
break;
}
}
}
// Print topological sort of the above created graph
g.topologicalSort();
}
// Driver program to test above functions
int main()
{
string words[] = {"caa", "aaa", "aab"};
printOrder(words, 3, 3);
return 0;
}
Run on IDE
Output:
cab
Time Complexity: The first step to create a graph takes O(n + alhpa) time where n is number of given words and
alpha is number of characters in given alphabet. The second step is also topological sorting. Note that there would be
alpha vertices and at-most (n-1) edges in the graph. The time complexity of topological sorting is O(V+E) which is O(n
+ aplha) here. So overall time complexity is O(n + aplha) + O(n + aplha) which is O(n + aplha).
Exercise:
}
return min;
}
// This function returns the smallest possible cost to
// reach station N-1 from station 0. This function mainly
// uses minCostRec().
int minCost(int cost[][N])
{
return minCostRec(cost, 0, N-1);
}
// Driver program to test above function
int main()
{
int cost[N][N] = { {0, 15, 80, 90},
{INF, 0, 40, 50},
{INF, INF, 0, 70},
{INF, INF, INF, 0}
};
cout << "The Minimum cost to reach station "
<< N << " is " << minCost(cost);
return 0;
}
Run on IDE
Output:
The Minimum cost to reach station 4 is 65
Time complexity of the above implementation is exponential as it tries every possible path from 0 to N-1. The above
solution solves same subrpoblems multiple times (it can be seen by drawing recursion tree for minCostPathRec(0, 5).
Since this problem has both properties of dynamic programming problems ((see this and this). Like other typical
Dynamic Programming(DP) problems, re-computations of same subproblems can be avoided by storing the solutions
to subproblems and solving problems in bottom up manner.
One dynamic programming solution is to create a 2D table and fill the table using above given recursive formula. The
extra space required in this solution would be O(N 2) and time complexity would be O(N3)
We can solve this problem using O(N) extra space and O(N 2) time. The idea is based on the fact that given input
matrix is a Directed Acyclic Graph (DAG). The shortest path in DAG can be calculated using the approach discussed
in below post.
Shortest Path in Directed Acyclic Graph
We need to do less work here compared to above mentioned post as we know topological sortingof the graph. The
topological sorting of vertices here is 0, 1, ..., N-1. Following is the idea once topological sorting is known.
The idea in below code is to first calculate min cost for station 1, then for station 2, and so on. These costs are stored
in an array dist[0...N-1].
1) The min cost for station 0 is 0, i.e., dist[0] = 0
2) The min cost for station 1 is cost[0][1], i.e., dist[1] = cost[0][1]
3) The min cost for station 2 is minimum of following two.
a) dist[0] + cost[0][2]
b) dist[1] + cost[1][2]
For example consider the board shown on right side (taken from here), the minimum number of dice throws required
to reach cell 30 from cell 1 is 3. Following are steps.
a) First throw two on dice to reach cell number 3 and then ladder to reach 22
b) Then throw 6 to reach 28.
c) Finally through 2 to reach 30.
There can be other solutions as well like (2, 2, 6), (2, 4, 4), (2, 3, 5).. etc.
We strongly recommend to minimize the browser and try this yourself first.
The idea is to consider the given snake and ladder board as a directed graph with number of vertices equal
to the number of cells in the board. The problem reduces to finding the shortest path in a graph. Every vertex
of the graph has an edge to next six vertices if next 6 vertices do not have a snake or ladder. If any of the
next six vertices has a snake or ladder, then the edge from current vertex goes to the top of the ladder or tail
of the snake. Since all edges are of equal weight, we can efficiently find shortest path using Breadth First
Search of the graph.
Following is C++ implementation of the above idea. The input is represented by two things, first is N which is number
of cells in the given board, second is an array move[0N-1] of size N. An entry move[i] is -1 if there is no snake and
no ladder from i, otherwise move[i] contains index of destination cell for the snake or the ladder at i.
// C++ program to find minimum number of dice throws required to
// reach last cell from first cell of a given snake and ladder
// board
#include<iostream>
#include <queue>
using namespace std;
// An entry in queue used in BFS
struct queueEntry
{
int v;
int dist;
// Vertex number
// Distance of this vertex from source
};
// This function returns minimum number of dice throws required to
// Reach last cell from 0'th cell in a snake and ladder game.
// move[] is an array of size N where N is no. of cells on board
// If there is no snake or ladder from cell i, then move[i] is -1
// Otherwise move[i] contains cell to which snake or ladder at i
// takes to.
int getMinDiceThrows(int move[], int N)
{
// The graph has N vertices. Mark all the vertices as
// not visited
bool *visited = new bool[N];
for (int i = 0; i < N; i++)
visited[i] = false;
// Create a queue for BFS
queue<queueEntry> q;
// Mark the node 0 as visited and enqueue it.
visited[0] = true;
queueEntry s = {0, 0}; // distance of 0't vertex is also 0
q.push(s); // Enqueue 0'th vertex
// Do a BFS starting from vertex at index 0
queueEntry qe; // A queue entry (qe)
while (!q.empty())
{
qe = q.front();
int v = qe.v; // vertex no. of queue entry
// If front vertex is the destination vertex,
// we are done
if (v == N-1)
break;
// Otherwise dequeue the front vertex and enqueue
// its adjacent vertices (or cell numbers reachable
// through a dice throw)
q.pop();
for (int j=v+1; j<=(v+6) && j<N; ++j)
{
// If this cell is already visited, then ignore
if (!visited[j])
{
// Otherwise calculate its distance and mark it
// as visited
queueEntry a;
a.dist = (qe.dist + 1);
visited[j] = true;
//
//
//
if
else
a.v = j;
q.push(a);
}
}
}
// We reach here when 'qe' has last vertex
// return the distance of vertex in 'qe'
return qe.dist;
}
// Driver program to test methods of graph class
int main()
{
// Let us construct the board given in above diagram
int N = 30;
int moves[N];
for (int i = 0; i<N; i++)
moves[i] = -1;
// Ladders
moves[2] = 21;
moves[4] = 7;
moves[10] = 25;
moves[19] = 28;
// Snakes
moves[26]
moves[20]
moves[16]
moves[18]
=
=
=
=
0;
8;
3;
6;
cout << "Min Dice throws required is " << getMinDiceThrows(moves, N);
return 0;
}
Run on IDE
Output:
Min Dice throws required is 3
We have discussed cycle detection for directed graph. We have also discussed a union-find algorithm for cycle
detection in undirected graphs. The time complexity of the union-find algorithm is O(ELogV). Like directed graphs, we
can use DFS to detect cycle in an undirected graph in O(V+E) time. We do a DFS traversal of the given graph. For
every visited vertex v, if there is an adjacent u such that u is already visited and u is not parent of v, then there is a
cycle in graph. If we dont find such an adjacent for any vertex, we say that there is no cycle. The assumption of this
approach is that there are no parallel edges between any two vertices.
// A C++ Program to detect cycle in an undirected graph
#include<iostream>
#include <list>
#include <limits.h>
using namespace std;
// Class for an undirected graph
class Graph
{
int V;
// No. of vertices
list<int> *adj;
// Pointer to an array containing adjacency lists
bool isCyclicUtil(int v, bool visited[], int parent);
public:
Graph(int V);
// Constructor
void addEdge(int v, int w);
// to add an edge to graph
bool isCyclic();
// returns true if there is a cycle
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to vs list.
adj[w].push_back(v); // Add v to ws list.
}
// A recursive function that uses visited[] and parent to detect
// cycle in subgraph reachable from vertex v.
bool Graph::isCyclicUtil(int v, bool visited[], int parent)
{
// Mark the current node as visited
visited[v] = true;
// Recur for all the vertices adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
{
// If an adjacent is not visited, then recur for that adjacent
if (!visited[*i])
{
if (isCyclicUtil(*i, visited, v))
return true;
}
// If an adjacent is visited and not parent of current vertex,
// then there is a cycle.
else if (*i != parent)
return true;
}
return false;
}
// Returns true if the graph contains a cycle, else false.
bool Graph::isCyclic()
{
// Mark all the vertices as not visited and not part of recursion
// stack
bool *visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to detect cycle in different
// DFS trees
for (int u = 0; u < V; u++)
if (!visited[u]) // Don't recur for u if it is already visited
if (isCyclicUtil(u, visited, -1))
return true;
return false;
}
// Driver program to test above functions
int main()
{
Graph g1(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 0);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.isCyclic()? cout << "Graph contains cycle\n":
cout << "Graph doesn't contain cycle\n";
Graph g2(3);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.isCyclic()? cout << "Graph contains cycle\n":
cout << "Graph doesn't contain cycle\n";
return 0;
}
Run on IDE
Output: