0% found this document useful (0 votes)
11 views40 pages

Design and Analysis of Algorithms - Report

The document discusses algorithms including Prim's algorithm, Kruskal's algorithm, and quicksort. Prim's algorithm finds the minimum spanning tree of a graph. Kruskal's algorithm also finds the minimum spanning tree. Quicksort sorts an array using partitioning and recursion.

Copyright:

© All Rights Reserved

Available Formats

Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
0% found this document useful (0 votes)
11 views40 pages

Design and Analysis of Algorithms - Report

The document discusses algorithms including Prim's algorithm, Kruskal's algorithm, and quicksort. Prim's algorithm finds the minimum spanning tree of a graph. Kruskal's algorithm also finds the minimum spanning tree. Quicksort sorts an array using partitioning and recursion.

Copyright:

© All Rights Reserved

Available Formats

Download as DOCX, PDF, TXT or read online on Scribd
Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1/ 40

Design and Analysis of Algorithms

Winter Semester-(2023-2024)
SCOPE
Lab Record

Registration No : 21BCE9125
Name : K.V.K SAI SUHAS
Programme Title : B-Tech CSE With cyber security
Course Code : CSE3004
Lab Slot : L31+L32
Faculty : Tanikella Divya Naga Pavani

Faculty Signature External Signature

1
S.no Algorithm Page. No
1 Prim’s 3
2 Kruskal 6
3 Quick Sort 10
4 Merge Sort 13
5 Matrix Multiplication 16
6 Strongly Connected Components 18
7 0/1 Knapsack Problem Greedy 21
8 All pair’s Shortest Path 23
9 Optimal Binary Search Tree 26
10 Travelling Sales Man Problem 29
11 Graph Colouring 34
12 Hamiltonian Circuit 37
13 Table of Time Complexities and Space Complexities 40

2
1.Prim’s algorithm

1.Aim of the Program:


The aim of this program is to find the minimum spanning tree of a given graph using Prim's
algorithm.

2. Algorithm:
Start with any vertex and mark it as visited.
Repeat until all vertices are visited:
Select the smallest edge that connects a visited vertex to an unvisited vertex.
Add this edge to the minimum spanning tree and mark the unvisited vertex as visited.
Continue until all vertices are visited.

3.Code:
import java.util.Arrays;
class PrimMinimumSpanningTree {
private static final int V = 5;
int minKey(int key[], Boolean mstSet[]) {
int min = Integer.MAX_VALUE, min_index = -1;
for (int v = 0; v < V; v++) {
if (!mstSet[v] && key[v] < min) {
min = key[v];
min_index = v;
}
}
return min_index;
}
void printMST(int parent[], int graph[][]) {
System.out.println("Edge \tWeight");
for (int i = 1; i < V; i++)
System.out.println(parent[i] + " - " + i + "\t" + graph[i][parent[i]]);
}

3
void primMST(int graph[][]) {
int parent[] = new int[V];
int key[] = new int[V];
Boolean mstSet[] = new Boolean[V];
Arrays.fill(key, Integer.MAX_VALUE);
Arrays.fill(mstSet, false);
key[0] = 0;
parent[0] = -1;
for (int count = 0; count < V - 1; count++) {
int u = minKey(key, mstSet);
mstSet[u] = true;
for (int v = 0; v < V; v++) {
if (graph[u][v] != 0 && !mstSet[v] && graph[u][v] < key[v]) {
parent[v] = u;
key[v] = graph[u][v];
}
}
}
printMST(parent, graph);
}
public static void main(String[] args) {
PrimMinimumSpanningTree t = new PrimMinimumSpanningTree();
int graph[][] = new int[][]{{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0}};
t.primMST(graph);
}
}

4
4.Output:

5.Time complexity:
The time complexity of Kruskal's algorithm is O(|E| log |V|), where |E| is the number of edges
in the graph and |V| is the number of vertices in the graph.
This is because the algorithm first sorts the edges in ascending order of their weights, which
takes O(|E| log |E|) time. Then, the algorithm iterates through the edges in sorted order,
adding them to the spanning tree if they do not create a cycle. This takes O(|E| log |V|) time,
since each edge can be added to the spanning tree in O(log |V|) time using a union-find data
structure.

5
2.Kruskal's algorithm
1.Aim of the Program:
The aim of this program is to implement Kruskal's algorithm, which is used to find the
minimum spanning tree of a connected, undirected graph.

2. Algorithm:
 Sort all the edges in non-decreasing order of their weight.
 Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far.
If not,
 include this edge. Otherwise, discard it.
 Repeat step 2 until there are (V-1) edges in the spanning tree, where V is the number
of vertices.

3.Code:
import java.util.*;
class Edge implements Comparable<Edge> {
int src, dest, weight;
public int compareTo(Edge compareEdge) {
return this.weight - compareEdge.weight;
}
};
class Subset {
int parent, rank;
};
class KruskalsAlgorithm {
int V, E;
Edge edge[];
KruskalsAlgorithm(int v, int e) {
V = v;
E = e;
edge = new Edge[E];
for (int i = 0; i < e; ++i)
edge[i] = new Edge();

6
}
int find(Subset subsets[], int i) {
if (subsets[i].parent != i)
subsets[i].parent = find(subsets, subsets[i].parent);
return subsets[i].parent;
}
void Union(Subset subsets[], int x, int y) {
int xroot = find(subsets, x);
int yroot = find(subsets, y);
if (subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
else {
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}

void KruskalMST() {
Edge result[] = new Edge[V];
int e = 0;
int i = 0;
for (i = 0; i < V; ++i)
result[i] = new Edge();
Arrays.sort(edge);
Subset subsets[] = new Subset[V];
for (i = 0; i < V; ++i)
subsets[i] = new Subset();

7
for (int v = 0; v < V; ++v) {
subsets[v].parent = v;
subsets[v].rank = 0;
}
i = 0;
while (e < V - 1) {
Edge next_edge = new Edge();
next_edge = edge[i++];
int x = find(subsets, next_edge.src);
int y = find(subsets, next_edge.dest);
if (x != y) {
result[e++] = next_edge;
Union(subsets, x, y);
}
}
System.out.println("Edges in the constructed MST:");
int minimumCost = 0;
for (i = 0; i < e; ++i) {
System.out.println(result[i].src + " -- " + result[i].dest + " == " + result[i].weight);
minimumCost += result[i].weight;
}
System.out.println("Minimum Cost Spanning Tree: " + minimumCost);
}

public static void main(String[] args) {


int V = 4;
int E = 5;
KruskalsAlgorithm graph = new KruskalsAlgorithm(V, E);
graph.edge[0].src = 0;

8
graph.edge[0].dest = 1;
graph.edge[0].weight = 10;
graph.edge[1].src = 0;
graph.edge[1].dest = 2;
graph.edge[1].weight = 6;
graph.edge[2].src = 0;
graph.edge[2].dest = 3;
graph.edge[2].weight = 5;
graph.edge[3].src = 1;
graph.edge[3].dest = 3;
graph.edge[3].weight = 15;
graph.edge[4].src = 2;
graph.edge[4].dest = 3;
graph.edge[4].weight = 4;
graph.KruskalMST();
}
}

4.Output:

5.Time complexity:
The time complexity of Prim's algorithm is O(|E| log |V|).
Here,
● |V| is the number of vertices in the graph.
● |E| is the number of edges in the graph.

9
3.QUICKSORT
1.Aim:
The aim is to sort a given list of elements using the Quick Sort algorithm.

2.Algorithm:
• Choose a pivot element from the list (usually the last element).
• Partition the list into two sublists: elements less than the pivot and elements greater than
the pivot.
• Recursively apply the same process to the sublists.
• Combine the sorted sublists to get the final sorted list.

3.Code
public class QuickSort {
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5};
int n = arr.length;
quickSort(arr, 0, n-1);
System.out.println("Sorted array:");
printArray(arr);
}
// Partition the array into two subarrays
static int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // Choose the last element as the pivot
int i = (low - 1); // Index of the smaller element
// Partition the array
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

10
}
// Swap the pivot element with the greater element
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i + 1; // Return the index of the pivot element
}
// Recursive function to sort the array
static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
// Print the sorted array
static void printArray(int[] arr) {
for (int i = 0; i < arr.length; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}

4.Output:

11
5.Time complexity:
The time complexity of Quick Sort is O(n log n) on average, where n is the number of
elements in the array. However, in the worst case (e.g., when the array is already sorted in
ascending or descending order), Quick Sort has a time complexity of O(n^2).
Quick Sort is an essential sorting algorithm due to its efficiency and widespread use in
various programming applications. Its divide-and-conquer approach allows for efficient
sorting of large arrays and is often the preferred choice for sorting when dealing with
extensive datasets.

12
4.Merge Sort
1.Aim:
The aim of the program is to implement the merge sort algorithm to efficiently sort a
given array of elements in ascending order.

2.Algorithm:
• Merge sort is a divide-and-conquer algorithm that works as follows:
• Divide the unsorted list into n sublists, each containing one element (a list of one
element is considered sorted).
• Repeatedly merge sublists to produce new sorted sublists until there is only one
sublist remaining. This will be the sorted list.

3.Code:
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int n = arr.length;
int[] temp = new int[n];
mergeSort(arr, temp, 0, n - 1);
}
private static void mergeSort(int[] arr, int[] temp, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, temp, left, mid);
mergeSort(arr, temp, mid + 1, right);
merge(arr, temp, left, mid, right);
}
}
private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
// Copy the elements from the original array to the temporary array

13
for (int i = left; i <= right; i++) {
temp[i] = arr[i];
}
int i = left; // Index for the left sublist
int j = mid + 1; // Index for the right sublist
int k = left; // Index for the merged array
// Merge the sublists
while (i <= mid && j <= right) {
if (temp[i] <= temp[j]) {
arr[k++] = temp[i++];
} else {
arr[k++] = temp[j++];
}
}
// Copy any remaining elements from the left sublist
while (i <= mid) {
arr[k++] = temp[i++];
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
mergeSort(arr);
System.out.print("Sorted array is: ");
for (int num : arr) {
System.out.print(num + " ");
}
}
}

14
4.Output:

5.Time complexity:
The merge sort algorithm has a time complexity of O(n log n), where n is the number of
elements in the array. This makes it one of the most efficient sorting algorithms available.

15
5. Matrix Chain Multiplication using
Dynamic Programming
1.Aim:
The aim of the provided code is to solve the matrix chain multiplication problem, which is
to find the most efficient way to multiply a chain of matrices. Specifically, the code aims to
determine the minimum number of scalar multiplications needed to compute the product of
matrices in the given chain.

2.Algorithm:
The algorithm used in the provided code is a recursive approach to solving the matrix chain
multiplication problem. It involves dividing the problem into subproblems and recursively
solving them. Here's the high-level overview of the algorithm:
• Base Case: If there's only one matrix in the chain (i.e., i == j), then no multiplication is
needed, so return 0.
• For each possible split point k in the chain (from i to j-1), recursively calculate the
minimum number of scalar multiplications needed for the two subchains: from i to k
and from k+1 to j.
• Compute the total number of scalar multiplications needed for the current split point
k and update the minimum if necessary.
• Return the minimum number of scalar multiplications.

3.Code:
class MatrixChainMultiplication {
static int MatrixChainOrder(int p[], int i, int j) {
if (i == j) {
return 0;
}
int min = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
int count = MatrixChainOrder(p, i, k) + MatrixChainOrder(p, k + 1, j) + p[i - 1] * p[k]
* p[j];
if (count < min) {

16
min = count;
}
}
return min;
}
public static void main(String args[]) {
int arr[] = new int[] {1, 2, 3, 4, 3};
int n = arr.length;
System.out.println("Minimum number of multiplications is " + MatrixChainOrder(arr, 1,
n - 1));
}}

4.Output

5.Time complexity:
The time complexity of the dynamic programming algorithm for matrix chain multiplication
is O(n^3), where n is the number of matrices. This is because the algorithm iterates over all
possible pairs of matrices and subchains, leading to a cubic running time.

17
6.Strongly connected components in a digraph
1.Aim:
The aim of this code is to find the strongly connected components (SCCs) in a directed
graph using the Kosaraju's algorithm. SCCs are subsets of vertices in a graph where every
vertex is reachable from every other vertex within the subset.

2.Algorithm:
The algorithm used in this code is based on Kosaraju's algorithm for finding strongly
connected components in a directed graph. Here's a summary of the algorithm:

First DFS (Depth First Search):


 Perform a DFS traversal on the graph.
 Track the finishing time of each node when it completes traversal.
 This step identifies the ordering of nodes based on their finishing times.

Transpose the Graph:


 Reverse all the edges in the graph.

Second DFS:
 Perform DFS traversal on the transposed graph.
 Use the finishing times obtained in the first step to process nodes in the reverse order.
 Identify the leader node of each SCC during this traversal.

3.Code:
import java.util.*;
class Graph {
private int V; // Number of vertices
private LinkedList<Integer>[] adj; // Adjacency list representation
private int time = 0;
Graph(int v) {
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList();
}
void addEdge(int v, int w) {
adj[v].add(w);
}
void SCCUtil(int u, int disc[], int low[], Stack<Integer> st, boolean stackMember[]) {
disc[u] = low[u] = ++time;
st.push(u);
stackMember[u] = true;

18
for (int v : adj[u]) {
if (disc[v] == -1) {
SCCUtil(v, disc, low, st, stackMember);
low[u] = Math.min(low[u], low[v]);
} else if (stackMember[v] == true) {
low[u] = Math.min(low[u], disc[v]);
}
}
int w = -1;
if (low[u] == disc[u]) {
while (w != u) {
w = st.pop();
System.out.print(w + " ");
stackMember[w] = false;
}
System.out.println();
}
}
void SCC() {
int disc[] = new int[V];
int low[] = new int[V];
boolean stackMember[] = new boolean[V];
Stack<Integer> st = new Stack<>();
Arrays.fill(disc, -1);
Arrays.fill(low, -1);
Arrays.fill(stackMember, false);

for (int i = 0; i < V; i++) {


if (disc[i] == -1)
SCCUtil(i, disc, low, st, stackMember);
}
}
public static void main(String args[]) {
Graph g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(1, 3);
g.addEdge(3, 4);

System.out.println("Strongly Connected Components:");


g.SCC();
}
}

19
4.Output:

5.Time complexity:
O(V + E), where V is the number of vertices and E is the number of edges.

20
7. 0/1 knapsack problem using the Greedy algorithm.
1.Aim:
The aim of the provided code is to solve the 0/1 Knapsack problem using a recursive
approach.

2.Algorithm:
The code implements a recursive approach to solve the 0/1 Knapsack problem. Here's a brief
overview of the algorithm:
• The function solveKnapsack takes four parameters: the knapsack capacity (capacity),
arrays of item weights (weights) and values (values), and the number of items
(itemCount).
• It starts with the base cases: if there are no items left (itemCount == 0) or the knapsack
capacity is 0 (capacity == 0), then the maximum value that can be obtained is 0.
• If the weight of the current item exceeds the knapsack capacity, the item cannot be
included in the knapsack. In this case, the function recurses with the next item
(reducing the itemCount by 1).
• If including the current item won't exceed the capacity, the function recurses twice:
• Once by including the current item and reducing the capacity accordingly.
• Once by excluding the current item.
• The function returns the maximum value obtained by either including or excluding the
current item.

3.Code
public class KnapsackSolver {
static int maximum(int x, int y) {
return (x > y) ? x : y;
}
static int solveKnapsack(int capacity, int weights[], int values[], int itemCount) {
if (itemCount == 0 || capacity == 0) {
return 0;
}
if (weights[itemCount - 1] > capacity) {

21
return solveKnapsack(capacity, weights, values, itemCount - 1);
} else {
return maximum(
values[itemCount - 1] + solveKnapsack(capacity - weights[itemCount - 1], weights,
values, itemCount - 1),
solveKnapsack(capacity, weights, values, itemCount - 1)
);
}
}
public static void main(String args[]) {
int values[] = new int[]{70, 80, 90};
int weights[] = new int[]{15, 25, 35};
int knapsackCapacity = 60;
int itemCount = values.length;
System.out.println(solveKnapsack(knapsackCapacity, weights, values, itemCount));
}
}

4.Output

5.Time complexity:
The Greedy algorithm for the 0/1 Knapsack problem has a time complexity of O(n log n),
where n is the number of items, due to the sorting of the items in the initialization step.

22
8.All Pairs Shortest Path Problem(Floyd Warshall Algorithm)
1.Aim:
The aim of the Floyd-Warshall algorithm is to find the shortest paths between all pairs of
vertices in a weighted graph.

2.Algorithm:
The Floyd-Warshall algorithm works by considering all pairs of vertices and gradually
updating
the shortest path distances between them. It iterates through all vertices and checks if there
is a shorter path between any two vertices that passes through the current vertex being
considered. If such a path exists, it updates the shortest distance accordingly. The algorithm
effectively builds a table of shortest distances between all pairs of vertices.
Here are the steps of the algorithm:
• Initialize a 2D array dist[][] where dist[i][j] represents the shortest distance between
vertices i and j.
• Initialize dist[][] with the weights of the edges in the graph. If there is no edge between
vertices i and j, set dist[i][j] to infinity.
• For each vertex k, iterate through all pairs of vertices i and j and update dist[i][j] to
min(dist[i][j], dist[i][k] + dist[k][j]). This step effectively checks if there is a shorter path
between vertices i and j by passing through vertex k.
• After the iterations, dist[][] will contain the shortest distances between all pairs of
vertices.

3.Code
public class AllPairsShortestPath {
static final int INF = Integer.MAX_VALUE;
public static int[][] floydWarshall(int[][] graph) {
int numVertices = graph.length;
int[][] dist = new int[numVertices][numVertices];
// Initialize dist[][] with the weights of the edges in the graph
for (int i = 0; i < numVertices; i++) {
for (int j = 0; j < numVertices; j++) {

23
dist[i][j] = graph[i][j];
}
}
for (int k = 0; k < numVertices; k++) {
for (int i = 0; i < numVertices; i++) {
for (int j = 0; j < numVertices; j++) {
if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
return dist;
}
public static void main(String[] args) {
int[][] graph = {
{0, 3, INF, INF, INF},
{INF, 0, 5, INF, INF},
{INF, INF, 0, INF, 2},
{2, INF, INF, 0, INF},
{INF, INF, INF, 1, 0}
};
int[][] shortestPaths = floydWarshall(graph);
System.out.println("Shortest paths between all pairs of vertices:");
for (int i = 0; i < shortestPaths.length; i++) {
for (int j = 0; j < shortestPaths[i].length; j++) {
if (shortestPaths[i][j] == INF) {
System.out.print("INF ");
} else {
System.out.print(shortestPaths[i][j] + " ");

24
}
}
System.out.println();
}
}
}

4.Output

5.Time Complexity:
The time complexity of the Floyd Warshall algorithm is O(n^3), where n is the number of
vertices in the graph

25
9. optimal binary search tree.
1. Aim:
Implement a Java program to solve the optimal binary search tree problem using
dynamic programming.

2.Algorithm:
• We construct a table where cost[i][j] represents the minimum cost of constructing a
binary search tree using keys from index i to j.
• Initialize this table with base cases.
• Iterate through all possible lengths of key sequences.
• For each length, iterate through all possible starting keys.
• Calculate the cost of each possible subtree and store the minimum cost.
• The minimum cost of constructing the optimal binary search tree is in cost[0][n-1],
where n is the number of keys.

3.Code:
import java.util.Arrays;
public class OptimalBST {
static int optimalBST(int keys[], int freq[]) {
int n = keys.length;
int[][] cost = new int[n + 1][n + 1];
// Initialize base cases
for (int i = 0; i < n; i++) {
cost[i][i] = freq[i];
}
// Iterate through all possible lengths of key sequences
for (int L = 1; L <= n; L++) {
// Iterate through all possible starting keys
for (int i = 0; i <= n - L; i++) {
int j = i + L - 1;
cost[i][j] = Integer.MAX_VALUE;
int sum = sum(freq, i, j);

26
// Calculate the cost of each possible subtree and store the minimum cost
for (int k = i; k <= j; k++) {
int c = ((k > i) ? cost[i][k - 1] : 0) + ((k < j) ? cost[k + 1][j] : 0) + sum;
if (c < cost[i][j]) {
cost[i][j] = c;
}
}
}
}

// The minimum cost of constructing the optimal binary search tree is in cost[0][n-1]
return cost[0][n - 1];
}
static int sum(int freq[], int i, int j) {
int s = 0;
for (int k = i; k <= j; k++) {
s += freq[k];
}
return s;
}
public static void main(String[] args) {
int keys[] = {10, 12, 20};
int freq[] = {34, 8, 50};
int result = optimalBST(keys, freq);
System.out.println("Minimum Cost: " + result);}}

27
4.Output:

5.Time complexities:
Worst case: O(n^3)
Best case: O(n^2)
Average case: O(n^3)

28
10. Program for solving a traveling salesperson's problem
(TSP)
1.Aim:
The aim of this problem is to find the shortest possible route that visits each city
exactly once and returns to the origin city.

2.Theory:
The Traveling Salesperson's Problem (TSP) is a classic optimization problem. It
involves finding the shortest possible route that visits every city exactly once and
returns to the original city. It's an NP-hard problem, meaning there's no known
polynomial-time solution for all instances. Brute force and dynamic
programming are two approaches to solving it.

(a) Brute Force Approach:


In the brute force approach, you generate all possible permutations of the cities
and calculate the total distance for each permutation. Finally, you select the
permutation with the minimum total distance.

3.Code:
import java.util.*;
public class TSPDynamicProgramming {
static int[][] graph;
static int n;
static int tspDynamicProgramming(int start) {
n = graph.length;
int[][] dp = new int[n][1 << n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < (1 << n); j++) {
dp[i][j] = Integer.MAX_VALUE;
}
}
for (int i = 0; i < n; i++) {
dp[i][1 << i] = 0;

29
}
for (int subset = 1; subset < (1 << n); subset++) {
for (int next = 0; next < n; next++) {
if ((subset & (1 << next)) == 0) {
continue;
}
for (int end = 0; end < n; end++) {
if (end == next || (subset & (1 << end)) == 0) {
continue;
}
int newDistance = dp[end][subset ^ (1 << next)] + graph[end][next];
dp[next][subset] = Math.min(dp[next][subset], newDistance);
}
}
}
int minDistance = Integer.MAX_VALUE;
for (int i = 1; i < n; i++) {
int distance = dp[i][(1 << n) - 1] + graph[i][start];
minDistance = Math.min(minDistance, distance);
}
return minDistance;
}
public static void main(String[] args) {
graph = new int[][]{
{0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};
int start = 0;

30
int result = tspDynamicProgramming(start);
System.out.println("Minimum distance: " + result);
}
}

4.Output:

5.Time Complexity:
Average: O(n^2*2^n)
Best: O(n^2*2^n)
Worst: O(n^2*2^n)

(b) Dynamic Programming Algorithm:


Dynamic programming is a more efficient approach compared to brute force. It
uses memoization to store solutions to subproblems and avoids redundant
calculations.2. Write a program for solving graph colouring problems
using backtracking.

Code:
public class TSPDynamicProgramming {
static int[][] graph;
static int n;
static int tspDynamicProgramming(int start, int mask, int[][] dp) {
if (mask == (1 << n) - 1) {
return graph[start][0];
}
if (dp[start][mask] != -1) {
return dp[start][mask];

31
}
int minDistance = Integer.MAX_VALUE;
for (int city = 0; city < n; city++) {
if ((mask & (1 << city)) == 0) {
int newMask = mask | (1 << city);
int distance = graph[start][city] + tspDynamicProgramming(city, newMask, dp);
minDistance = Math.min(minDistance, distance);
}
}
return dp[start][mask] = minDistance;
}
public static void main(String[] args) {
graph = new int[][]{
{0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};
n = graph.length;
int start = 0;
int[][] dp = new int[n][1 << n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < (1 << n); j++) {
dp[i][j] = -1;
}
}
int shortestDistance = tspDynamicProgramming(start, 1, dp);
System.out.println("Shortest Distance: " + shortestDistance);
}
}

32
4.Output:

5.Time complexities:
Average: O(n^2 * 2^n)
Best: O(n^2 * 2^n)
Worst: O(n^2 * 2^n)

33
11.Graph colouring problem using backtracking.
1.Aim:
The aim of this problem is to assign colors to vertices of a graph in such a way
that no two adjacent vertices have the same color using the minimum number
of colors.

2.Theory:
Graph coloring is a fundamental problem in graph theory. It involves assigning
colors to the vertices of a graph in such a way that no two adjacent vertices share
the same color. Backtracking is commonly used to solve this problem.

3.Code:
import java.util.Arrays;
public class GraphColoring {
static boolean isSafe(int v, int graph[][], int colors[], int c) {
for (int i = 0; i < graph.length; i++) {
if (graph[v][i] == 1 && c == colors[i]) {
return false;
}
}
return true;
}
static boolean graphColoringUtil(int graph[][], int m, int colors[], int v) {
if (v == graph.length) {
return true;
}
for (int c = 1; c <= m; c++) {
if (isSafe(v, graph, colors, c)) {
colors[v] = c;
if (graphColoringUtil(graph, m, colors, v + 1)) {
return true;
}

34
colors[v] = 0;
}
}
return false;
}

static boolean graphColoring(int graph[][], int m) {


int[] colors = new int[graph.length];
Arrays.fill(colors, 0);
if (!graphColoringUtil(graph, m, colors, 0)) {
System.out.println("No solution exists.");
return false;
}
System.out.println("Solution exists. Vertex colors:");
for (int i = 0; i < graph.length; i++) {
System.out.println("Vertex " + i + " : Color " + colors[i]);
}
return true;
}

public static void main(String[] args) {


int graph[][] = {
{0, 1, 1, 1},
{1, 0, 1, 0},
{1, 1, 0, 1},
{1, 0, 1, 0}
};
int m = 3;
graphColoring(graph, m);
}

35
}

4.Output:

5.Time Complexity:
Worst-case time complexity: O(m^n)
Average-case time complexity: O(m^n)
Best-case time complexity: O(m^n)

36
12.Hamiltonian circuit in a given graph.
1.Aim:
The aim of this problem is to find a closed loop in a graph that visits every vertex
exactly once.

2.Theory:
A Hamiltonian Circuit is a closed loop that visits every vertex exactly once in a
graph. Finding a Hamiltonian Circuit is NP-complete, meaning that there's no
known efficient algorithm to solve it for all graphs. Backtracking is often used to
find Hamiltonian Circuits in graphs.

3.Code:
import java.util.Arrays;

public class HamiltonianCircuit {


static boolean isSafe(int v, int graph[][], int path[], int pos) {
// Check if the edge exists and the vertex is not already in the path
if (graph[path[pos - 1]][v] == 0 || Arrays.asList(path).contains(v)) {
return false;
}
return true;
}

static boolean hamiltonianCycleUtil(int graph[][], int path[], int pos, int n) {


// If the path has n vertices, check if the last vertex connects to the first vertex
if (pos == n) {
if (graph[path[n - 1]][path[0]] == 1) {
return true;
} else {
return false;
}
}

37
// Try all vertices for the next position in the path
for (int v = 1; v < n; v++) {
if (isSafe(v, graph, path, pos)) {
path[pos] = v;
// Recursively check if the rest of the path can be completed
if (hamiltonianCycleUtil(graph, path, pos + 1, n)) {
return true;
}
// If not, reset the current position in the path
path[pos] = -1;
}
}
return false;
}

static boolean hamiltonianCycle(int graph[][], int n) {


int[] path = new int[n];
Arrays.fill(path, -1);
path[0] = 0;
// Start the backtracking search from the first vertex
if (!hamiltonianCycleUtil(graph, path, 1, n)) {
System.out.println("No Hamiltonian Cycle exists.");
return false;
}
System.out.println("Hamiltonian Cycle exists. Path:");
for (int i = 0; i < n; i++) {
System.out.print(path[i] + " ");
}
System.out.println(path[0]);
return true;

38
}
public static void main(String[] args) {
int graph[][] = {
{0, 1, 1, 1},
{1, 0, 1, 0},
{1, 1, 0, 1},
{1, 0, 1, 0}
};
int n = graph.length;
hamiltonianCycle(graph, n);
}
}

4.Output:

5.Time Complexity:
Worst-case time complexity: O(N!)
Average-case time complexity: O(N!)
Best-case time complexity: O(N!)

39
13. Time Complexities and Space Complexities
Algorithm Time Best Average Worst Space Best Average Worst case
Complexity Case Case Case Complexity Case Case
Prim’s O(ElogV) O(E +Vlog V) O(E+Vlog O(E + VlogV) O(V + E) O(V + E) O(V + E) O(V + E)
V)
Kruskal O(E log E) O(E log E) O(E log E) O(E log E) O(V + E) or O(V + E) O(V + E) O(E)
or O(E log O(E)
V)
Merge Sort O(n log n) O(n log n) O(n log n) O(n log n) O(n) O(n) O(n) O(n)
Quick Sort O(n log n) O(n log n) O(n log n) O(n^2) O(n log n) O(n log n) O(n log n) O(n)
Matrix O(n^3) O(n^3) O(n^3) O(n^3) O(n^2) O(n^2) O(n^2) O(n^2)
Multiplicati
on
Strongly O(V + E) O(V + E) O(V + E) O(V + E) O(V) O(V) O(V) O(V)
Connected
Components
0/1 O(n log n) O(n log n) O(n log n) O(n log n) O(n) O(n) O(n) O(n)
Knapsack
Problem
Greedy
All pair’s O(V^3) O(V^3) O(V^3) O(V^3) O(V^2) O(V^2) O(V^2) O(V^2)
Shortest
Path
Optimal O(n^3) O(n^2) O(n^3) O(n^3) O(n^2) O(n^2) O(n^2) O(n^2)
Binary
Search Tree
Travelling O(n!) O(n!) O(n!) O(n!) O(n) O(n) O(n) O(n)
Sales Man
Problem(Br
ute Force
Approach)
Travelling O(n^2*2^n) O(n^2*2^n) O(n^2*2^n) O(n^2*2^n) O(n^2*2^n) O(n^2*2^ O(n^2*2^n) O(n^2*2^n)
Sales Man n)
Problem(Dy
namic
Programmin
g)
Graph O(mV) O(V) O(m^V) O(m^V) O(V) O(V) O(V) O(V)
Coloring
Hamiltonian O(V!) O(1) O(V!) O(V!) O(V) O(V) O(V) O(V)
Circuit

40

You might also like