CHADALAWADA RAMANAMMA ENGINEERING COLLEGE
(AUTONOMOUS)
(23A05302P) ADVANCED DATA STRUCTURES & ALGORITHM ANALYSIS LAB
Course Objectives:The objective of the course is to
Acquire practical skills in constructing and managing Data structures
Apply the popular algorithm design methods in problem-solving scenarios
Course Outcomes:After completion of the course, students will be able to
Design and develop programs to solve real world problems with the popular algorithm
design methods. (L5)
Demonstrate an understanding of Non-Linear data structures by developing
implementing the operations on AVL Trees, B-Trees, Heaps and Graphs. (L2)
Critically assess the design choices and implementation strategies of algorithms and
data structures in complex applications. (L5)
Utilize appropriate data structures and algorithms to optimize solutions for specific
computational problems. (L3)
Compare the performance of different of algorithm design strategies (L4)
Design algorithms to new real world problems (L6)
Sample Programs:
1. Construct an AVL tree for a given set of elements which are stored in a file. And
implement insert and delete operation on the constructed tree. Write contents of tree
into a new file using in-order.
2. Construct B-Tree an order of 5 with a set of 100 random elements stored in array.
Implement searching, insertion and deletion operations.
3. Construct Min and Max Heap using arrays, delete any element and display the content
of the Heap.
4. Implement BFT and DFT for given graph, when graph is represented by
a) Adjacency Matrix b) Adjacency Lists
5. Write a program for finding the bi-connected components in a given graph.
6. Implement Quick sort and Merge sort and observe the execution time for various
input sizes (Average, Worst and Best cases).
7. Compare the performance of Single Source Shortest Paths using Greedy method when
the graph is represented by adjacency matrix and adjacency lists.
8. Implement Job sequencing with deadlines using Greedy strategy.
9. Write a program to solve 0/1 Knapsack problem Using Dynamic Programming.
10. Implement N-Queens Problem Using Backtracking.
11. Use Backtracking strategy to solve 0/1 Knapsack problem.
12. Implement Travelling Sales Person problem using Branch and Bound approach.
Reference Books:
1. Fundamentals of Data Structures in C++, Horowitz Ellis, SahniSartaj, Mehta,
Dinesh, 2ndEdition, Universities Press
2. Computer Algorithms/C++ Ellis Horowitz, SartajSahni,
SanguthevarRajasekaran, 2ndEdition, University Press
3. Data Structures and program design in C, Robert Kruse, Pearson Education Asia
4. An introduction to Data Structures with applications, Trembley& Sorenson,
McGraw Hill
Online Learning Resources:
1. http://cse01-iiith.vlabs.ac.in/
http://peterindia.net/Algorithms.html
2
1. Construct an AVL tree for a given set of elements which are stored in a file. And
implement insert and delete operation on the constructed tree. Write contents of tree into a
new file using in-order.
AIM of the Program
The aim of this program is to implement an AVL Tree (Adelson-Velsky and Landis Tree), a self-
balancing Binary Search Tree (BST), using C programming. The AVL Tree maintains its
balance by ensuring the height difference between the left and right subtrees of any node is at
most 1, which guarantees O(log n) time complexity for insertion, deletion, and search operations.
Objectives of the Program:
1. Insertion: To insert a new node into the AVL Tree while maintaining its balanced
property.
2. Deletion: To remove a node from the AVL Tree and adjust the tree to maintain its
balanced property.
3. Traversal: To perform in-order traversal of the AVL Tree, which will display the nodes
in ascending order.
4. Self-Balancing Property: To implement the necessary rotations (left, right, left-right,
and right-left) to ensure the AVL Tree remains balanced after every insertion or deletion
operation.
5. Memory Management: To efficiently manage memory allocation and deallocation for
the AVL Tree nodes to prevent memory leaks.
Algorithm for AVL Tree Operations
1. Initialize
Set root to NULL.
2. Insert Operation
Input: Key to be inserted.
Process:
1. If the tree is empty (root == NULL), create a new node and assign it as root.
2. If the tree is not empty, find the correct position to insert the new node following
Binary Search Tree (BST) insertion rules.
3. Insert the new node and update the height of the affected nodes.
3
4. Check the balance factor of the affected nodes and perform appropriate rotations
to maintain the AVL property:
Left-Left Case: Perform a right rotation.
Right-Right Case: Perform a left rotation.
Left-Right Case: Perform a left rotation followed by a right rotation.
Right-Left Case: Perform a right rotation followed by a left rotation.
Output: Updated tree with the new node inserted.
3. Delete Operation
Input: Key to be deleted.
Process:
1. If the tree is empty (root == NULL), return.
2. If the tree is not empty, find the node to be deleted using BST deletion rules.
3. If the node to be deleted has one child or no child:
Remove the node and adjust the pointers.
4. If the node to be deleted has two children:
Find the inorder successor (smallest node in the right subtree).
Replace the node's data with the inorder successor's data.
Delete the inorder successor.
5. Update the height of the affected nodes.
6. Check the balance factor of the affected nodes and perform appropriate rotations
to maintain the AVL property.
Output: Updated tree with the node deleted.
4. In-order Traversal
Input: Root of the tree.
Process:
1. Recursively traverse the left subtree.
4
2. Visit the root node.
3. Recursively traverse the right subtree.
Output: All nodes of the tree in ascending order.
5. Exit
Process:
1. Free all the memory allocated for the tree nodes.
2. End the program.
PROGRAM:
// Including necessary header files
#include <stdio.h>
#include <stdlib.h>
// Structure for a tree node
struct TreeNode {
int data;
struct TreeNode* left;
struct TreeNode* right;
int height; // Height of the node
};
// Function to get the height of a node
int height(struct TreeNode* node) {
if (node == NULL)
return 0;
return node->height;
}
5
// Function to get the maximum of two integers
int max(int a, int b) {
return (a > b) ? a : b;
}
// Function to create a new node with a given key
struct TreeNode* createNode(int key) {
struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
if (newNode != NULL) {
newNode->data = key;
newNode->left = NULL;
newNode->right = NULL;
newNode->height = 1; // New node is initially at height 1
}
return newNode;
}
// Function to right rotate subtree rooted with y
struct TreeNode* rightRotate(struct TreeNode* y) {
struct TreeNode* x = y->left;
struct TreeNode* T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right)) + 1;
6
x->height = max(height(x->left), height(x->right)) + 1;
// Return new root
return x;
}
// Function to left rotate subtree rooted with x
struct TreeNode* leftRotate(struct TreeNode* x) {
struct TreeNode* y = x->right;
struct TreeNode* T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right)) + 1;
y->height = max(height(y->left), height(y->right)) + 1;
// Return new root
return y;
}
// Function to get the balance factor of a node
int getBalance(struct TreeNode* node) {
if (node == NULL)
return 0;
return height(node->left) - height(node->right);
7
}
// Function to insert a key into the AVL tree
struct TreeNode* insert(struct TreeNode* root, int key) {
// Perform standard BST insert
if (root == NULL)
return createNode(key);
if (key < root->data)
root->left = insert(root->left, key);
else if (key > root->data)
root->right = insert(root->right, key);
else // Duplicate keys not allowed
return root;
// Update height of the current node
root->height = 1 + max(height(root->left), height(root->right));
// Get the balance factor to check whether this node became unbalanced
int balance = getBalance(root);
// Left Left Case
if (balance > 1 && key < root->left->data)
return rightRotate(root);
// Right Right Case
if (balance < -1 && key > root->right->data)
return leftRotate(root);
8
// Left Right Case
if (balance > 1 && key > root->left->data) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Left Case
if (balance < -1 && key < root->right->data) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
// Return the unchanged node pointer
return root;
}
// Function to find the node with the minimum value
struct TreeNode* minValueNode(struct TreeNode* node) {
struct TreeNode* current = node;
while (current->left != NULL)
current = current->left;
return current;
}
// Function to delete a key from the AVL tree
struct TreeNode* deleteNode(struct TreeNode* root, int key) {
if (root == NULL)
9
return root;
// Perform standard BST delete
if (key < root->data)
root->left = deleteNode(root->left, key);
else if (key > root->data)
root->right = deleteNode(root->right, key);
else {
// Node with only one child or no child
if ((root->left == NULL) || (root->right == NULL)) {
struct TreeNode* temp = root->left ? root->left : root->right;
// No child case
if (temp == NULL) {
temp = root;
root = NULL;
} else // One child case
*root = *temp; // Copy the contents of the non-empty child
free(temp);
} else {
// Node with two children, get the inorder successor
struct TreeNode* temp = minValueNode(root->right);
// Copy the inorder successor's data to this node
root->data = temp->data;
// Delete the inorder successor
10
root->right = deleteNode(root->right, temp->data);
}
}
// If the tree had only one node, then return
if (root == NULL)
return root;
// Update height of the current node
root->height = 1 + max(height(root->left), height(root->right));
// Get the balance factor to check whether this node became unbalanced
int balance = getBalance(root);
// Left Left Case
if (balance > 1 && getBalance(root->left) >= 0)
return rightRotate(root);
// Left Right Case
if (balance > 1 && getBalance(root->left) < 0) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Right Case
if (balance < -1 && getBalance(root->right) <= 0)
return leftRotate(root);
11
// Right Left Case
if (balance < -1 && getBalance(root->right) > 0) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// Function to perform in-order traversal of the AVL tree
void inOrderTraversal(struct TreeNode* root) {
if (root != NULL) {
inOrderTraversal(root->left);
printf("%d ", root->data);
inOrderTraversal(root->right);
}
}
// Function to free the memory allocated for the AVL tree
void freeAVLTree(struct TreeNode* root) {
if (root != NULL) {
freeAVLTree(root->left);
freeAVLTree(root->right);
free(root);
}
}
int main() {
12
struct TreeNode* root = NULL;
int choice, key;
do {
printf("\nAVL Tree Operations:\n");
printf("1. Insert a node\n");
printf("2. Delete a node\n");
printf("3. In-order Traversal\n");
printf("4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter the key to insert: ");
scanf("%d", &key);
root = insert(root, key);
break;
case 2:
printf("Enter the key to delete: ");
scanf("%d", &key);
root = deleteNode(root, key);
break;
case 3:
printf("In-order Traversal: ");
inOrderTraversal(root);
printf("\n");
break;
13
case 4:
// Free allocated memory
freeAVLTree(root);
printf("Exiting...\n");
break;
default:
printf("Invalid choice! Please enter a valid option.\n");
}
} while (choice != 4);
return 0;
}
OUTPUT:
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 1
Enter the key to insert: 5
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 1
14
Enter the key to insert: 7
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 1
Enter the key to insert: 8
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 3
In-order Traversal: 5 7 8
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 2
Enter the key to delete: 5
AVL Tree Operations:
1. Insert a node
15
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 3
In-order Traversal: 7 8
AVL Tree Operations:
1. Insert a node
2. Delete a node
3. In-order Traversal
4. Exit
Enter your choice: 4
Exiting...
2.Construct B-Tree an order of 5 with a set of 100 random elements stored in array.
Implement searching, insertion and deletion operations.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#define ORDER 5
#define T (ORDER / 2) // Minimum degree
// B-Tree node structure
typedef struct BTreeNode {
int keys[ORDER - 1];
struct BTreeNode *children[ORDER];
int numKeys;
int isLeaf;
} BTreeNode;
16
// Function to create a new B-Tree node
BTreeNode* createNode(int isLeaf) {
BTreeNode* node = (BTreeNode*)malloc(sizeof(BTreeNode));
node->isLeaf = isLeaf;
node->numKeys = 0;
for (int i = 0; i < ORDER; i++) {
node->children[i] = NULL;
}
return node;
}
// Function to traverse the B-Tree
void traverse(BTreeNode* root) {
if (root != NULL) {
int i;
for (i = 0; i < root->numKeys; i++) {
if (!root->isLeaf) {
traverse(root->children[i]);
}
printf("%d ", root->keys[i]);
}
if (!root->isLeaf) {
traverse(root->children[i]);
}
}
}
// Function to search a key in the B-Tree
BTreeNode* search(BTreeNode* root, int key) {
17
if (root == NULL) return NULL;
int i = 0;
while (i < root->numKeys && key > root->keys[i]) {
i++;
}
if (i < root->numKeys && root->keys[i] == key) {
return root;
}
if (root->isLeaf) {
return NULL;
}
return search(root->children[i], key);
}
// Function to insert a key into a non-full node
void insertNonFull(BTreeNode* root, int key) {
int i = root->numKeys - 1;
if (root->isLeaf) {
while (i >= 0 && key < root->keys[i]) {
root->keys[i + 1] = root->keys[i];
i--;
}
root->keys[i + 1] = key;
root->numKeys++;
} else {
while (i >= 0 && key < root->keys[i]) {
i--;
}
i++;
if (root->children[i]->numKeys == ORDER - 1) {
18
// Split child if full
BTreeNode* child = root->children[i];
BTreeNode* newChild = createNode(child->isLeaf);
int median = T - 1;
// Copy keys to newChild
for (int j = 0; j < T - 1; j++) {
newChild->keys[j] = child->keys[j + T];
}
if (!child->isLeaf) {
for (int j = 0; j < T; j++) {
newChild->children[j] = child->children[j + T];
}
}
child->numKeys = T - 1;
newChild->numKeys = T - 1;
// Insert newChild into parent
for (int j = root->numKeys; j >= i; j--) {
root->children[j + 1] = root->children[j];
}
root->children[i + 1] = newChild;
for (int j = root->numKeys - 1; j >= i; j--) {
root->keys[j + 1] = root->keys[j];
}
root->keys[i] = child->keys[T - 1];
root->numKeys++;
}
19
insertNonFull(root->children[i], key);
}
}
// Function to insert a key into the B-Tree
void insert(BTreeNode** root, int key) {
BTreeNode* r = *root;
if (r->numKeys == ORDER - 1) {
BTreeNode* s = createNode(0);
*root = s;
s->children[0] = r;
s->isLeaf = 0;
splitChild(s, 0);
insertNonFull(s, key);
} else {
insertNonFull(r, key);
}
}
// Function to split a child of a node
void splitChild(BTreeNode* parent, int i) {
BTreeNode* fullChild = parent->children[i];
BTreeNode* newChild = createNode(fullChild->isLeaf);
int median = T - 1;
// Copy keys to newChild
for (int j = 0; j < median; j++) {
newChild->keys[j] = fullChild->keys[j + T];
}
if (!fullChild->isLeaf) {
20
for (int j = 0; j < T; j++) {
newChild->children[j] = fullChild->children[j + T];
}
}
fullChild->numKeys = median;
newChild->numKeys = median;
for (int j = parent->numKeys; j >= i; j--) {
parent->children[j + 1] = parent->children[j];
}
parent->children[i + 1] = newChild;
for (int j = parent->numKeys - 1; j >= i; j--) {
parent->keys[j + 1] = parent->keys[j];
}
parent->keys[i] = fullChild->keys[median];
parent->numKeys++;
}
// Main function to demonstrate B-Tree operations
int main() {
BTreeNode* root = createNode(1); // Start with a leaf node
// Insert random elements
for (int i = 0; i < 100; i++) {
int key = rand() % 1000; // Random key between 0 and 999
insert(&root, key);
}
21
printf("B-Tree traversal:\n");
traverse(root);
printf("\n");
// Example search
int keyToSearch = rand() % 1000;
BTreeNode* searchResult = search(root, keyToSearch);
if (searchResult) {
printf("Key %d found in B-Tree.\n", keyToSearch);
} else {
printf("Key %d not found in B-Tree.\n", keyToSearch);
}
return 0;
}
OUTPUT:
B-Tree traversal:
5 15 25 30 35 40 45 50 60 70 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150
155 160 165 170 175 180 185 190 195 200 205 210 215 220 225 230 235 240 245 250 255
260 265 270 275 280 285 290 295 300 305 310 315 320 325 330 335 340 345 350 355 360
365 370 375 380 385 390 395 400 405 410 415 420 425 430 435 440 445 450 455 460 465
470 475 480 485 490 495 500
Key 250 found in B-Tree.
3)A)Construct Min and Max Heap using arrays, delete any element and display the content
of the Heap.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
22
// Function prototypes
void heapify(int heap[], int size, int i);
void buildHeap(int heap[], int size);
void deleteElement(int heap[], int *size, int index);
void displayHeap(int heap[], int size);
void swap(int *a, int *b);
int main() {
int heap[MAX_SIZE];
int size, choice, index;
// Input size of the heap
printf("Enter the number of elements in the heap: ");
scanf("%d", &size);
// Input elements of the heap
printf("Enter %d elements:\n", size);
for (int i = 0; i < size; i++) {
scanf("%d", &heap[i]);
}
// Build the Min Heap
buildHeap(heap, size);
printf("Min Heap built successfully:\n");
displayHeap(heap, size);
// Delete an element
printf("Enter the index of the element to delete (0-based index): ");
23
scanf("%d", &index);
if (index < 0 || index >= size) {
printf("Invalid index!\n");
} else {
deleteElement(heap, &size, index);
printf("Heap after deletion:\n");
displayHeap(heap, size);
}
return 0;
}
// Function to swap two elements
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// Function to heapify the subtree rooted at index i
void heapify(int heap[], int size, int i) {
int smallest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < size && heap[left] < heap[smallest]) {
smallest = left;
}
24
if (right < size && heap[right] < heap[smallest]) {
smallest = right;
}
if (smallest != i) {
swap(&heap[i], &heap[smallest]);
heapify(heap, size, smallest);
}
}
// Function to build the Min Heap from an unordered array
void buildHeap(int heap[], int size) {
for (int i = size / 2 - 1; i >= 0; i--) {
heapify(heap, size, i);
}
}
// Function to delete an element from the Min Heap
void deleteElement(int heap[], int *size, int index) {
if (*size <= 0) {
printf("Heap is empty!\n");
return;
}
if (index >= *size) {
printf("Index out of range!\n");
return;
}
// Replace the element at index with the last element
25
heap[index] = heap[*size - 1];
(*size)--;
// Heapify the root to maintain the heap property
heapify(heap, *size, index);
}
// Function to display the contents of the heap
void displayHeap(int heap[], int size) {
if (size == 0) {
printf("Heap is empty.\n");
return;
}
printf("Heap elements are:\n");
for (int i = 0; i < size; i++) {
printf("%d ", heap[i]);
}
printf("\n");
}
OUTPUT:
Enter the number of elements in the heap: 7
Enter 7 elements:
10 20 15 30 40 50 100
Min Heap built successfully:
10 20 15 30 40 50 100
Enter the index of the element to delete (0-based index): 2
Heap after deletion:
10 20 100 30 40 50
26
3)B)Construct Max Heap using arrays, delete any element and display the content of the
Heap.
PROGRAM:
#include <stdio.h>
// Function prototypes
void heapify(int arr[], int n, int i);
void buildMaxHeap(int arr[], int n);
void deleteRoot(int arr[], int *n);
void displayHeap(int arr[], int n);
// Main function
int main() {
int heap[] = {10, 20, 15, 30, 40, 50, 100, 25, 45};
int size = sizeof(heap) / sizeof(heap[0]);
printf("Original heap:\n");
displayHeap(heap, size);
// Build max heap
buildMaxHeap(heap, size);
printf("\nMax heap constructed:\n");
displayHeap(heap, size);
// Delete root of the heap
deleteRoot(heap, &size);
printf("\nHeap after deleting root:\n");
displayHeap(heap, size);
return 0;
27
}
// Function to maintain the heap property
void heapify(int arr[], int n, int i) {
int largest = i; // Initialize largest as root
int left = 2 * i + 1; // left = 2*i + 1
int right = 2 * i + 2; // right = 2*i + 2
// Check if left child exists and is greater than root
if (left < n && arr[left] > arr[largest])
largest = left;
// Check if right child exists and is greater than root
if (right < n && arr[right] > arr[largest])
largest = right;
// If largest is not root
if (largest != i) {
int temp = arr[i];
arr[i] = arr[largest];
arr[largest] = temp;
// Recursively heapify the affected subtree
heapify(arr, n, largest);
}
}
// Function to build a max heap from an array
void buildMaxHeap(int arr[], int n) {
// Index of last non-leaf node
28
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
}
// Function to delete the root of the heap (the maximum element)
void deleteRoot(int arr[], int *n) {
if (*n <= 0)
return;
// Move the last element to the root
arr[0] = arr[*n - 1];
(*n)--;
// Heapify the root node
heapify(arr, *n, 0);
}
// Function to display the contents of the heap
void displayHeap(int arr[], int n) {
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
OUTPUT:
Original heap:
10 20 15 30 40 50 100 25 45
Max heap constructed:
100 45 50 30 40 15 10 25 20
29
Heap after deleting root:
50 45 20 30 40 15 10 25
4. Implement BFT and DFT for given graph, when graph is represented by
A)Adjacency Matrix b) Adjacency Lists
4.A) Adjacency Matrix
Program
#include <stdio.h>
#include <stdbool.h>
#define MAX 100
void bft(int adj[MAX][MAX], int start, int n);
void dft(int adj[MAX][MAX], int start, bool visited[], int n);
void dftUtil(int adj[MAX][MAX], int start, bool visited[], int n);
void bft(int adj[MAX][MAX], int start, int n) {
bool visited[MAX] = {false};
int queue[MAX], front = 0, rear = 0;
printf("BFT starting from vertex %d: ", start);
queue[rear++] = start;
visited[start] = true;
while (front < rear) {
int u = queue[front++];
printf("%d ", u);
30
for (int v = 0; v < n; v++) {
if (adj[u][v] && !visited[v]) {
queue[rear++] = v;
visited[v] = true;
}
}
}
printf("\n");
}
void dftUtil(int adj[MAX][MAX], int start, bool visited[], int n) {
visited[start] = true;
printf("%d ", start);
for (int v = 0; v < n; v++) {
if (adj[start][v] && !visited[v]) {
dftUtil(adj, v, visited, n);
}
}
}
void dft(int adj[MAX][MAX], int start, int n) {
bool visited[MAX] = {false};
printf("DFT starting from vertex %d: ", start);
dftUtil(adj, start, visited, n);
printf("\n");
31
}
int main() {
int n, m;
printf("Enter the number of vertices: ");
scanf("%d", &n);
printf("Enter the number of edges: ");
scanf("%d", &m);
int adj[MAX][MAX] = {0};
printf("Enter the edges (u v):\n");
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
adj[u][v] = 1;
adj[v][u] = 1; // For undirected graph
}
int startVertex;
printf("Enter the starting vertex for BFT and DFT: ");
scanf("%d", &startVertex);
bft(adj, startVertex, n);
dft(adj, startVertex, n);
return 0;
}
32
INPUT:
Enter the number of vertices:
5
Enter the number of edges:
6
Enter the edges (u v):
01
04
12
13
23
34
Enter the starting vertex for BFT and DFT: 0
OUTPUT:
BFT starting from vertex 0: 0 1 4 2 3
DFT starting from vertex 0: 0 1 2 3 4
B) Adjacency Lists
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX 100
typedef struct Node {
int vertex;
struct Node* next;
33
} Node;
typedef struct Graph {
Node* adjLists[MAX];
int numVertices;
} Graph;
Node* createNode(int vertex);
void addEdge(Graph* graph, int src, int dest);
void bft(Graph* graph, int start);
void dft(Graph* graph, int start, bool visited[]);
void dftUtil(Graph* graph, int start, bool visited[]);
Node* createNode(int vertex) {
Node* newNode = malloc(sizeof(Node));
newNode->vertex = vertex;
newNode->next = NULL;
return newNode;
}
void addEdge(Graph* graph, int src, int dest) {
Node* newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
34
}
void bft(Graph* graph, int start) {
bool visited[MAX] = {false};
int queue[MAX], front = 0, rear = 0;
printf("BFT starting from vertex %d: ", start);
queue[rear++] = start;
visited[start] = true;
while (front < rear) {
int vertex = queue[front++];
printf("%d ", vertex);
Node* temp = graph->adjLists[vertex];
while (temp) {
int adjVertex = temp->vertex;
if (!visited[adjVertex]) {
queue[rear++] = adjVertex;
visited[adjVertex] = true;
}
temp = temp->next;
}
}
printf("\n");
}
void dftUtil(Graph* graph, int vertex, bool visited[]) {
35
visited[vertex] = true;
printf("%d ", vertex);
Node* temp = graph->adjLists[vertex];
while (temp) {
int adjVertex = temp->vertex;
if (!visited[adjVertex]) {
dftUtil(graph, adjVertex, visited);
}
temp = temp->next;
}
}
void dft(Graph* graph, int start) {
bool visited[MAX] = {false};
printf("DFT starting from vertex %d: ", start);
dftUtil(graph, start, visited);
printf("\n");
}
int main() {
Graph* graph = malloc(sizeof(Graph));
for (int i = 0; i < MAX; i++) {
graph->adjLists[i] = NULL;
}
int n, m;
36
printf("Enter the number of vertices: ");
scanf("%d", &n);
graph->numVertices = n;
printf("Enter the number of edges: ");
scanf("%d", &m);
printf("Enter the edges (u v):\n");
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
addEdge(graph, u, v);
}
int startVertex;
printf("Enter the starting vertex for BFT and DFT: ");
scanf("%d", &startVertex);
bft(graph, startVertex);
dft(graph, startVertex);
return 0;
}
INPUT:
Enter the number of vertices:
5
Enter the number of edges:
6
37
Enter the edges (u v):
01
04
12
13
23
34
Enter the starting vertex for BFT and DFT: 0
OUTPUT:
BFT starting from vertex 0: 0 1 4 2 3
DFT starting from vertex 0: 0 1 2 3 4
5.Write a program for finding the bi-connected components in a given graph.
PROGRAM
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX 100
int n, m, time;
int low[MAX], disc[MAX], parent[MAX], stack[MAX], top;
bool visited[MAX];
bool ap[MAX]; // To store articulation points
typedef struct {
int u, v;
38
} Edge;
Edge edges[MAX];
void init() {
time = 0;
top = -1;
for (int i = 0; i < MAX; i++) {
disc[i] = low[i] = -1;
parent[i] = -1;
visited[i] = false;
ap[i] = false;
}
}
void tarjan(int u, int adj[MAX][MAX], int V) {
int children = 0;
disc[u] = low[u] = ++time;
visited[u] = true;
stack[++top] = u;
for (int v = 0; v < V; v++) {
if (adj[u][v]) {
if (disc[v] == -1) {
children++;
parent[v] = u;
tarjan(v, adj, V);
low[u] = (low[u] < low[v]) ? low[u] : low[v];
39
if ((parent[u] == -1 && children > 1) || (parent[u] != -1 && low[v] >= disc[u])) {
while (stack[top] != v) {
printf("%d ", stack[top--]);
}
printf("%d\n", stack[top--]);
}
} else if (v != parent[u]) {
low[u] = (low[u] < disc[v]) ? low[u] : disc[v];
}
}
}
}
int main() {
printf("Enter the number of vertices and edges: ");
scanf("%d %d", &n, &m);
int adj[MAX][MAX] = {0};
printf("Enter the edges (u v):\n");
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
adj[u][v] = adj[v][u] = 1;
}
init();
40
for (int i = 0; i < n; i++) {
if (disc[i] == -1) {
tarjan(i, adj, n);
}
}
return 0;
}
INPUT:
Enter the number of vertices and edges:
55
01
12
20
13
34
OUTPUT:
012
134
6)A) Write a c program to Implement Quick sort observe the execution time for various
input sizes (Average, Worst and Best cases)
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Function to swap two elements
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
41
*b = temp;
}
// Partition function for Quick Sort
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
// Quick Sort function
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);
}
}
// Function to generate a random array
void generateRandomArray(int arr[], int size) {
42
for (int i = 0; i < size; i++) {
arr[i] = rand() % 10000; // Random numbers between 0 and 9999
}
}
// Function to generate a sorted array (best case scenario)
void generateSortedArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] = i;
}
}
// Function to generate a reverse sorted array (worst case scenario)
void generateReverseSortedArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] = size - i - 1;
}
}
// Function to print array
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
srand(time(NULL)); // Seed for random number generation
43
int sizes[] = {100, 1000, 10000}; // Different sizes for testing
int numSizes = sizeof(sizes) / sizeof(sizes[0]);
for (int s = 0; s < numSizes; s++) {
int size = sizes[s];
int *arr = (int *)malloc(size * sizeof(int));
// Best Case: Sorted Array
generateSortedArray(arr, size);
clock_t start = clock();
quickSort(arr, 0, size - 1);
clock_t end = clock();
double timeBest = (double)(end - start) / CLOCKS_PER_SEC;
printf("Best Case (Sorted) - Time taken for size %d: %f seconds\n", size, timeBest);
// Average Case: Random Array
generateRandomArray(arr, size);
start = clock();
quickSort(arr, 0, size - 1);
end = clock();
double timeAverage = (double)(end - start) / CLOCKS_PER_SEC;
printf("Average Case (Random) - Time taken for size %d: %f seconds\n", size,
timeAverage);
// Worst Case: Reverse Sorted Array
generateReverseSortedArray(arr, size);
start = clock();
quickSort(arr, 0, size - 1);
end = clock();
double timeWorst = (double)(end - start) / CLOCKS_PER_SEC;
44
printf("Worst Case (Reverse Sorted) - Time taken for size %d: %f seconds\n", size,
timeWorst);
free(arr);
}
return 0;
}OUTPUT:
Best Case (Sorted) - Time taken for size 100: 0.000XXX seconds
Average Case (Random) - Time taken for size 100: 0.000YYY seconds
Worst Case (Reverse Sorted) - Time taken for size 100: 0.000ZZZ seconds
Best Case (Sorted) - Time taken for size 1000: 0.001XXX seconds
Average Case (Random) - Time taken for size 1000: 0.002YYY seconds
Worst Case (Reverse Sorted) - Time taken for size 1000: 0.003ZZZ seconds
Best Case (Sorted) - Time taken for size 10000: 0.020XXX seconds
Average Case (Random) - Time taken for size 10000: 0.025YYY seconds
Worst Case (Reverse Sorted) - Time taken for size 10000: 0.030ZZZ seconds
6)B) Write a c program to Implement Merge sort observe the execution time for various
input sizes (Average, Worst and Best cases)
PROGRAM
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Function to merge two subarrays
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
45
// Create temporary arrays
int* L = (int*)malloc(n1 * sizeof(int));
int* R = (int*)malloc(n2 * sizeof(int));
// Copy data to temporary arrays L[] and R[]
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
// Merge the temporary arrays back into arr[left..right]
int i = 0; // Initial index of first subarray
int j = 0; // Initial index of second subarray
int k = left; // Initial index of merged subarray
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of L[], if any
while (i < n1) {
arr[k] = L[i];
i++;
46
k++;
}
// Copy the remaining elements of R[], if any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
// Free the temporary arrays
free(L);
free(R);
}
// Merge Sort function
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
// Function to generate a random array
void generateRandomArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
47
arr[i] = rand() % 10000; // Random numbers between 0 and 9999
}
}
// Function to generate a sorted array (best case scenario)
void generateSortedArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] = i;
}
}
// Function to generate a reverse sorted array (worst case scenario)
void generateReverseSortedArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] = size - i - 1;
}
}
// Function to print array
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
srand(time(NULL)); // Seed for random number generation
int sizes[] = {100, 1000, 10000}; // Different sizes for testing
48
int numSizes = sizeof(sizes) / sizeof(sizes[0]);
for (int s = 0; s < numSizes; s++) {
int size = sizes[s];
int* arr = (int*)malloc(size * sizeof(int));
// Best Case: Sorted Array
generateSortedArray(arr, size);
clock_t start = clock();
mergeSort(arr, 0, size - 1);
clock_t end = clock();
double timeBest = (double)(end - start) / CLOCKS_PER_SEC;
printf("Best Case (Sorted) - Time taken for size %d: %f seconds\n", size, timeBest);
// Average Case: Random Array
generateRandomArray(arr, size);
start = clock();
mergeSort(arr, 0, size - 1);
end = clock();
double timeAverage = (double)(end - start) / CLOCKS_PER_SEC;
printf("Average Case (Random) - Time taken for size %d: %f seconds\n", size,
timeAverage);
// Worst Case: Reverse Sorted Array
generateReverseSortedArray(arr, size);
start = clock();
mergeSort(arr, 0, size - 1);
end = clock();
double timeWorst = (double)(end - start) / CLOCKS_PER_SEC;
printf("Worst Case (Reverse Sorted) - Time taken for size %d: %f seconds\n", size,
timeWorst);
49
free(arr);
}
return 0;
}
OUTPUT
Best Case (Sorted) - Time taken for size 100: 0.000XYZ seconds
Average Case (Random) - Time taken for size 100: 0.000ABC seconds
Worst Case (Reverse Sorted) - Time taken for size 100: 0.000DEF seconds
Best Case (Sorted) - Time taken for size 1000: 0.001XYZ seconds
Average Case (Random) - Time taken for size 1000: 0.002ABC seconds
Worst Case (Reverse Sorted) - Time taken for size 1000: 0.003DEF seconds
Best Case (Sorted) - Time taken for size 10000: 0.020XYZ seconds
Average Case (Random) - Time taken for size 10000: 0.025ABC seconds
Worst Case (Reverse Sorted) - Time taken for size 10000: 0.030DEF seconds
7.Compare the performance of Single Source Shortest Paths using Greedy method when the
graph is represented by adjacency matrix and adjacency lists.
PROGRAM
// Adjacency Matrix representation in C
#include <stdio.h>
#define V 4
// Initialize the matrix to zero
void init(int arr[][V]) {
int i, j;
50
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
arr[i][j] = 0;
}
// Add edges
void addEdge(int arr[][V], int i, int j) {
arr[i][j] = 1;
arr[j][i] = 1;
}
// Print the matrix
void printAdjMatrix(int arr[][V]) {
int i, j;
for (i = 0; i < V; i++) {
printf("%d: ", i);
for (j = 0; j < V; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main() {
int adjMatrix[V][V];
init(adjMatrix);
addEdge(adjMatrix, 0, 1);
addEdge(adjMatrix, 0, 2);
51
addEdge(adjMatrix, 1, 2);
addEdge(adjMatrix, 2, 0);
addEdge(adjMatrix, 2, 3);
printAdjMatrix(adjMatrix);
return 0;
}
OUTPUT
0: 0 1 1 0
1: 1 0 1 0
2: 1 1 0 1
3: 0 0 1 0
8.Implement Job sequencing with deadlines using Greedy strategy.
Algorithm
Step1 − Find the maximum deadline value from the input set
of jobs.
Step2 − Once, the deadline is decided, arrange the jobs
in descending order of their profits.
Step3 − Selects the jobs with highest profits, their time
periods not exceeding the maximum deadline.
Step4 − The selected set of jobs are the output.
PROGRAM
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// A structure to represent a Jobs
typedef struct Jobs {
char id; // Jobs Id
int dead; // Deadline of Jobs
int profit; // Profit if Jobs is over before or on deadline
52
} Jobs;
// This function is used for sorting all Jobss according to
// profit
int compare(const void* a, const void* b){
Jobs* temp1 = (Jobs*)a;
Jobs* temp2 = (Jobs*)b;
return (temp2->profit - temp1->profit);
}
// Find minimum between two numbers.
int min(int num1, int num2){
return (num1 > num2) ? num2 : num1;
}
int main(){
Jobs arr[] = {
{ 'a', 2, 100 },
{ 'b', 2, 20 },
{ 'c', 1, 40 },
{ 'd', 3, 35 },
{ 'e', 1, 25 }
};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Following is maximum profit sequence of Jobs: \n");
qsort(arr, n, sizeof(Jobs), compare);
int result[n]; // To store result sequence of Jobs
bool slot[n]; // To keep track of free time slots
// Initialize all slots to be free
for (int i = 0; i < n; i++)
slot[i] = false;
// Iterate through all given Jobs
for (int i = 0; i < n; i++) {
// Find a free slot for this Job
for (int j = min(n, arr[i].dead) - 1; j >= 0; j--) {
// Free slot found
if (slot[j] == false) {
result[j] = i;
slot[j] = true;
break;
}
}
}
53
// Print the result
for (int i = 0; i < n; i++)
if (slot[i])
printf("%c ", arr[result[i]].id);
return 0;
}
Output
Following is maximum profit sequence of Jobs:
cad
9.Write a program to solve 0/1 Knapsack problem Using Dynamic Programming.
#include <stdio.h>
#define MAX_ITEMS 100
int knapsack(int weights[], int values[], int numItems, int capacity) {
int dp[numItems + 1][capacity + 1];
// Initialize the DP table
for (int i = 0; i <= numItems; i++) {
for (int w = 0; w <= capacity; w++) {
if (i == 0 || w == 0)
dp[i][w] = 0;
else if (weights[i - 1] <= w)
dp[i][w] = (values[i - 1] > (dp[i - 1][w - weights[i - 1]] + values[i - 1]) ? values[i - 1] :
dp[i - 1][w - weights[i - 1]] + values[i - 1]);
else
dp[i][w] = dp[i - 1][w];
}
}
return dp[numItems][capacity];
}
54
int main() {
int numItems, capacity;
printf("Enter the number of items: ");
scanf("%d", &numItems);
int weights[numItems];
int values[numItems];
printf("Enter the maximum weight capacity of the knapsack: ");
scanf("%d", &capacity);
printf("Enter the weights of the items:\n");
for (int i = 0; i < numItems; i++) {
scanf("%d", &weights[i]);
}
printf("Enter the values of the items:\n");
for (int i = 0; i < numItems; i++) {
scanf("%d", &values[i]);
}
int maxValue = knapsack(weights, values, numItems, capacity);
printf("Maximum value achievable: %d\n", maxValue);
return 0;
55
}
INPUT:
Enter the number of items: 4
Enter the maximum weight capacity of the knapsack: 7
Enter the weights of the items:
1238
Enter the values of the items:
20 5 10 40
OUTPUT:
Maximum value achievable: 60
10.Implement N-Queens Problem Using Backtracking.
#include <stdio.h>
#include <stdbool.h>
#define MAX 20
int board[MAX][MAX];
int N; // Size of the chessboard
// Function to print the chessboard
void printBoard() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (board[i][j] == 1)
printf("Q ");
else
printf(". ");
}
printf("\n");
}
56
printf("\n");
}
// Function to check if a queen can be placed at board[row][col]
bool isSafe(int row, int col) {
int i, j;
// Check this row on the left side
for (i = 0; i < col; i++) {
if (board[row][i] == 1)
return false;
}
// Check upper diagonal on the left side
for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 1)
return false;
}
// Check lower diagonal on the left side
for (i = row, j = col; j >= 0 && i < N; i++, j--) {
if (board[i][j] == 1)
return false;
}
return true;
}
57
// Function to solve the N-Queens problem using backtracking
bool solveNQueens(int col) {
if (col >= N)
return true;
for (int i = 0; i < N; i++) {
if (isSafe(i, col)) {
board[i][col] = 1; // Place queen
if (solveNQueens(col + 1))
return true;
board[i][col] = 0; // Backtrack
}
}
return false;
}
int main() {
printf("Enter the value of N (size of the chessboard): ");
scanf("%d", &N);
// Initialize the board with 0
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
board[i][j] = 0;
}
58
}
if (solveNQueens(0)) {
printf("One of the solutions for %d-Queens is:\n", N);
printBoard();
} else {
printf("No solution exists for %d-Queens.\n", N);
}
return 0;
}
Input
Enter the value of N (size of the chessboard): 4
Output:
One of the solutions for 4-Queens is:
Q...
..Q.
.Q..
...Q
11.Use Backtracking strategy to solve 0/1 Knapsack problem.
#include <stdio.h>
#define MAX_ITEMS 100
int numItems;
int weights[MAX_ITEMS];
int values[MAX_ITEMS];
int maxWeight;
// Function to calculate the maximum value using backtracking
void knapsack(int currentItem, int currentWeight, int currentValue, int *maxValue) {
59
// Base case: All items have been considered
if (currentItem == numItems) {
if (currentValue > *maxValue) {
*maxValue = currentValue;
}
return;
}
// Case 1: Exclude the current item
knapsack(currentItem + 1, currentWeight, currentValue, maxValue);
// Case 2: Include the current item (if it fits in the knapsack)
if (currentWeight + weights[currentItem] <= maxWeight) {
knapsack(currentItem + 1, currentWeight + weights[currentItem], currentValue +
values[currentItem], maxValue);
}
}
int main() {
int i, maxValue = 0;
printf("Enter the number of items: ");
scanf("%d", &numItems);
printf("Enter the maximum weight of the knapsack: ");
scanf("%d", &maxWeight);
printf("Enter the weights of the items:\n");
for (i = 0; i < numItems; i++) {
60
scanf("%d", &weights[i]);
}
printf("Enter the values of the items:\n");
for (i = 0; i < numItems; i++) {
scanf("%d", &values[i]);
}
knapsack(0, 0, 0, &maxValue);
printf("Maximum value achievable: %d\n", maxValue);
return 0;
}
Input:
Enter the number of items: 4
Enter the maximum weight of the knapsack: 7
Enter the weights of the items:
1238
Enter the values of the items:
20 5 10 40
Output:
Maximum value achievable: 60
12. Implement Travelling Sales Person problem using Branch and Bound approach.
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#include <float.h>
61
#define MAX 10
#define INF INT_MAX
int n; // Number of cities
int dist[MAX][MAX]; // Distance matrix
int bestPath[MAX]; // To store the best path
int currPath[MAX]; // To store the current path
int visited[MAX]; // To track visited cities
// Function to find the minimum cost path using branch and bound
void tspBranchBound(int currPos, int count, int cost, int bound) {
// If all cities are visited and there is a return path to the starting city
if (count == n && dist[currPos][0]) {
if (cost + dist[currPos][0] < bestPath[0]) {
bestPath[0] = cost + dist[currPos][0];
// Copy the current path to best path
for (int i = 0; i < n; i++) {
bestPath[i + 1] = currPath[i];
}
bestPath[n] = 0; // Return to the starting city
}
return;
}
// Branching
for (int i = 0; i < n; i++) {
if (!visited[i] && dist[currPos][i] != INF) {
// Calculate the new bound
int tempBound = bound;
int tempCost = cost + dist[currPos][i];
62
// Add the minimum cost edge to the bound
int min1 = INF, min2 = INF;
for (int j = 0; j < n; j++) {
if (dist[i][j] < min1 && i != j) {
min2 = min1;
min1 = dist[i][j];
} else if (dist[i][j] < min2 && i != j && dist[i][j] != min1) {
min2 = dist[i][j];
}
}
// If no valid edge exists
if (min1 == INF || min2 == INF) {
return;
}
tempBound -= (min1 + min2) / 2;
// Check if the new bound is promising
if (tempCost + tempBound < bestPath[0]) {
// Mark as visited
visited[i] = true;
currPath[count] = i;
// Recursive call
tspBranchBound(i, count + 1, tempCost, tempBound);
// Unmark as visited
visited[i] = false;
}
63
}
}
}
int main() {
printf("Enter the number of cities: ");
scanf("%d", &n);
printf("Enter the distance matrix:\n");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &dist[i][j]);
if (i != j && dist[i][j] == 0) {
dist[i][j] = INF; // No path
}
}
}
// Initialize the best path with a high value
bestPath[0] = INF;
for (int i = 1; i <= n; i++) {
bestPath[i] = -1;
}
// Initialize visited array and current path
for (int i = 0; i < n; i++) {
visited[i] = false;
currPath[i] = -1;
64
}
// Starting from the first city
visited[0] = true;
currPath[0] = 0;
// Initial bound (using a naive approach)
int initialBound = 0;
for (int i = 0; i < n; i++) {
int min1 = INF, min2 = INF;
for (int j = 0; j < n; j++) {
if (dist[i][j] < min1 && i != j) {
min2 = min1;
min1 = dist[i][j];
} else if (dist[i][j] < min2 && i != j && dist[i][j] != min1) {
min2 = dist[i][j];
}
}
if (min1 != INF) {
initialBound += (min1 + min2) / 2;
}
}
tspBranchBound(0, 1, 0, initialBound);
printf("Minimum cost: %d\n", bestPath[0]);
printf("Path: ");
for (int i = 0; i <= n; i++) {
65
printf("%d ", bestPath[i]);
}
printf("\n");
return 0;
}
Sample Input
Let's say we have 4 cities with the following distance matrix:
Enter the number of cities: 4
Enter the distance matrix:
0 10 15 20
10 0 35 25
15 35 0 30
20 25 30 0
OUTPUT:
Minimum cost: 80
Path: 0 1 3 2 0
66