0% found this document useful (0 votes)
50 views74 pages

AI Data Science Lab Exercises Guide

The document outlines a practical course on the Design and Analysis of Algorithms for the Department of Artificial Intelligence and Data Science, detailing various algorithmic techniques such as Divide and Conquer, Greedy Methods, and Dynamic Programming. It includes specific exercises like Binary Search, Knapsack Problem, and Minimum Spanning Trees using Prim's and Kruskal's algorithms, along with pseudocode and C programming implementations. Each section provides aims, pseudocode, program examples, and complexity analyses for the respective algorithms.

Uploaded by

sridharshan402
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views74 pages

AI Data Science Lab Exercises Guide

The document outlines a practical course on the Design and Analysis of Algorithms for the Department of Artificial Intelligence and Data Science, detailing various algorithmic techniques such as Divide and Conquer, Greedy Methods, and Dynamic Programming. It includes specific exercises like Binary Search, Knapsack Problem, and Minimum Spanning Trees using Prim's and Kruskal's algorithms, along with pseudocode and C programming implementations. Each section provides aims, pseudocode, program examples, and complexity analyses for the respective algorithms.

Uploaded by

sridharshan402
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

DEPARTMENT OF ARTIFICIAL INTELLIGENCE AND DATA SCIENCE

Practical Course Name

Design and Analysis of Algorithm

Laboratory

Practical Course Code


:
U23CSBC01

Year / Semester
:
II Year / III Semester

Department : ARTIFICIAL INTELLIGENCE AND DATA SCIENCE

[Link] [Link]
TABLE OF CONTENTS

[Link] DATE TITLE OF THR EXERCISE PAGE MARK SIGNATURE


NO

DIVIDE AND CONQUER METHOD (UNIT-IV)

1 BINARY SEARCH

2
FIND MAXIMUM AND
MINIMUM
GREEDY METHOD (UNIT IV)

3
KNAPSACK
4
MINIMUM SPANNING TREE
USINGPRIM’S ALGORITHM
5
MINIMUM SPANNING
TREE USINGKRUSKAL’S
ALGORITHM
6
SINGLE SOURCE SHORTEST
PATHS
DYNAMIC PROGRAMMING (UNIT V)

7 ALL PAIR SHORTEST PATHS

8 TRAVELING SALESMAN
PROBLEM
BACKTRACKING METHOD (UNIT V)

9 N QUEEN OR 8 QUEENS
PROBLEM
10 SUM OF SUBSETS
TABLE OF CONTENTS

[Link] DATE TITLE OF THR EXERCISE PAGE MARK SIGNATURE


NO

BRANCH AND BOUND (UNIT V)

11 TRAVELING SALESMAN
PROBLEM

CONTENT BEYOND THE SYLLABUS

12 TELECOMMUNICATION
NETWORK DESIGN
13 GRID-BASED ROBOTIC PATH
PLANNING
14 SUDOKU SOLVER

15 VEHICLE ROUTINGPROBLEM
Divide-and-Conquer
Technique
Divide and Conquer Algorithm involves breaking a larger problem into smaller subproblems, solving them
independently, and then combining their solutions to solve the original problem. The basic idea is to
recursively divide the problem into smaller subproblems until they become simple enough to be solved
directly. Once the solutions to the subproblems are obtained, they are then combined to produce the overall
solution.
Working of Divide and Conquer Algorithm:
The divide and Conquer Algorithm can be divided into three steps: Divide, Conquer, and Merge.
1. Divide:
Break down the original problem into smaller subproblems.
Each subproblem should represent a part of the overall problem.
The goal is to divide the problem until no further division is possible.
2. Conquer:
Solve each of the smaller subproblems individually.
If a subproblem is small enough (often referred to as the “base case”), we solve it directly without further
recursion.
The goal is to find solutions for these subproblems independently.
3. Merge:
Combine the sub-problems to get the final solution of the whole problem.
Once the smaller subproblems are solved, we recursively combine their solutions to get the solution to a
larger problem.
The goal is to formulate a solution for the original problem by merging the results from the subproblems.
Example Problems:
1. Binary search
2. Merge Sort
3. Quick Sort
4. Finding the maximum and minimum elements in an array
[Link]: BINARY SEARCH
DATE :

AIM:

To find whether the given element is found in the array or not using the divide and conquer algorithm

PSEUDOCODE:

Binary_Search(a, lower_bound, upper_bound, val)


/* 'a' is the given array, 'lower_bound' is the index of the first array element, 'upper_bound' is the index of the last
array element, 'val' is the value to search */
Step 1: set beg = lower_bound, end = upper_bound, pos = - 1
Step 2: repeat steps 3 and 4 while beg <=end
Step 3: set mid = (beg + end)/2
Step 4: if a[mid] = val
set pos = mid
print pos
go to step 6
else if a[mid] > val
set end = mid - 1
else
set beg = mid + 1
[end of if]
[end of loop]
Step 5: if pos = -1
print "value is not present in the array"
[end of if]
Step 6: exit
PROGRAM:
#include<stdio.h>
int a[20],flag=0;
int binarySearch(int a[20],int low,int high, int key)
{

int mid;
if(low<=high)
{
mid=(low+high)/2;
if(a[mid]==key)
{
return mid;
}
if(key<a[mid])
{
return(binarySearch(a,low,mid-1,key));
}
if(key>a[mid])
{
return(binarySearch(a,mid+1,high,key));
}
}
return -1;
}
int main()
{
int i,key,n,res;
printf("\nEnter the number of elements\n");
scanf("%d",&n);
printf("\nEnter the array elements\n");
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
printf("Enter the key to be searched\n");
scanf("%d",&key);
res=binarySearch(a,0,n-1,key);
if(res==-1)
{
printf("\nElement %d is not found in the array",key);
return 0;
}
printf("\nElement %d is found at posisiton\t%d in the array",key,res);
return 0;
}
INPUT/OUTPUT:

Binary Search in C

Complexity Analysis

 Time Complexity: O(log n)


o Each comparison allows the algorithm to halve the search space, so the time complexity is
logarithmic.
 Space Complexity: O(1)
o The algorithm uses a constant amount of space, regardless of the input size.

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Using the divide and conquer algorithm whether the given element is found in the array or not
[Link]: FINDING MAXIMUM AND MINIMUM
DATE:

AIM:

To find the maximum and minimum element in an array using divide and conquer method

PSEUDOCODE:

MinMax(A, n){
int min = A[0];
int max = A[0];
for(int i = 1; i < n; i++){
if(max < A[i])
max = A[i];
else if(min > A[i])
min = A[i];
}
return (min, max);
}
Step 1: Find the mid of the array.
Step 2: Find the maximum and minimum of the left subarray recursively.
Step 3: Find the maximum and minimum of the right subarray recursively.
Step 4: Compare the result of step 3 and step 4
Step 5: Return the minimum and maximum.
PROGRAM:

#include<stdio.h>
#include<stdio.h>
int max, min;
int a[100];
void maxmin(int i, int j)
{
int max1, min1, mid; if(i==j)
{
max = min = a[i];
}
else
{
if(i == j-1)
{
if(a[i] <a[j])
{
max = a[j];
min = a[i];
}
else
{
max = a[i];
min = a[j];
}
}
else

mid = (i+j)/2; maxmin(i, mid);


max1 = max; min1 = min; maxmin(mid+1, j); if(max <max1)
max = max1; if(min > min1) min = min1;
}}}
int main ()
{
int i, num;
printf ("\nEnter the total number of numbers : "); scanf ("%d",&num);
printf ("Enter the numbers : \n");
for (i=1;i<=num;i++)
scanf ("%d",&a[i]); max = a[0];
min = a[0]; maxmin(1, num);
printf ("Minimum element in an array : %d\n", min);
printf ("Maximum element in an array : %d\n", max); return 0;
}
INPUT/OUTPUT:

Finding max and minimum

Time Complexity:

 The recurrence relation for the divide and conquer approach in this problem is: T(n)=2T(n/2)+Θ(1)
 This simplifies to Θ(n) using the Master Theorem, which means the time complexity is linear.

Space Complexity:

 The space complexity is primarily due to the recursive stack space used. In the worst case, the depth of the
recursion tree is log n so the space complexity O(log n).

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the maximum and minimum element in the array is found.


Greedy Technique
A greedy algorithm is a type of optimization algorithm that makes locally optimal choices at each step to find a
globally optimal solution. It operates on the principle of “taking the best option now” without considering the long-
term consequences.
Steps for Creating a Greedy Algorithm
Define the problem: Clearly statethe problem to be solved and the objective to be optimized.
Identify the greedy choice: Determine the locally optimal choice at each step based on the current state.
Make the greedy choice: Select the greedy choice and update the current state.
Repeat: Continue making greedy choices until a solution is reached.
Following the given steps, one can learn how to use greedy algorithms to find optimal solutions.
Greedy Algorithm Examples
Fractional Knapsack: Optimizes the value of items that can be fractionally included in a knapsack with limited
capacity.
Dijkstra’s algorithm: Finds the shortest path from a source vertexto all other vertices in a weighted graph.
Prim’s and Kruskal’s algorithm: Finds the minimum spanning tree of a weighted graph.
Huffman coding: Compresses data byassigning shorter codes to more frequent symbols.
[Link]: KNAPSACK
DATE:

AIM:
To solve the knapsack problem using greedy algorithm

PSEUDOCODE:

Fractional Knapsack (Array W, Array V, int M)


1. for i <- 1 to size (V)
2. calculate cost[i] <- V[i] / W[i]
3. Sort-Descending (cost)
4. i ← 1
5. while (i <= size(V))
6. if W[i] <= M
7. M ← M – W[i]
8. total ← total + V[i];
9. if W[i] > M
10. i ← i+1
PROGRAM:

#include <stdio.h>

int main() {
float weight[50], profit[50], ratio[50], Totalvalue = 0, temp, capacity, amount;
int n, i, j;

printf("Enter the number of items: ");


scanf("%d", &n);

for (i = 0; i < n; i++) {


printf("Enter Weight and Profit for item[%d]:\n", i);
scanf("%f %f", &weight[i], &profit[i]);
}

printf("Enter the capacity of knapsack: ");


scanf("%f", &capacity);

for (i = 0; i < n; i++)


ratio[i] = profit[i] / weight[i];

// Sorting items based on the ratio in descending order


for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (ratio[i] < ratio[j]) {
temp = ratio[j];
ratio[j] = ratio[i];
ratio[i] = temp;

temp = weight[j];
weight[j] = weight[i];
weight[i] = temp;

temp = profit[j];
profit[j] = profit[i];
profit[i] = temp;
}
}
}
printf("Knapsack problem using Greedy Algorithm:\n");
printf("Items chosen (index, fraction):\n");
for (i = 0; i < n; i++) {
if (weight[i] > capacity)
break;
else {
Totalvalue += profit[i];
capacity -= weight[i];
printf("%d, 1.0\n", i);
}
}
if (i < n) {
Totalvalue += (ratio[i] * capacity);
printf("%d, %.2f\n", i, capacity / weight[i]);
}

printf("\nThe maximum value is: %f\n", Totalvalue);


return 0;
}

Knapsack

The given program uses a greedy approach to solve the fractional knapsack problem. Let's analyze the time
complexity step by step:

1. Input Reading:
o Reading the number of items (n): O(1)
o Reading the weights and profits of n items: O(n)
2. Ratio Calculation:
o Calculating the ratio of profit to weight for each item: O(n)
3. Sorting:
o The program sorts the items based on the ratio in descending order. The sorting algorithm used here
is a simple nested loop for selection sort which has a time complexity of O(n2 ).
4. Knapsack Filling:
o The loop iterates over the sorted items to fill the knapsack: O(n)

Combining these steps, the overall time complexity is dominated by the sorting step:O(n2 )

Space Complexity

The space complexity of the program includes:

1. Input Storage:
o Arrays weight, profit, and ratio, each of size n: O(n) for each, so O(3n)=O(n)
2. Auxiliary Variables:
o Variables like Totalvalue, temp, capacity, amount, n, i, j are all constants: O(1)

Since the primary storage requirement grows linearly with the number of items, the overall space complexity is:
O(n)
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the knapsack problem is solved using greedy algorithm.


[Link]: MINIMUM SPANNING TREE USING PRIM’S
DATE:

AIM:
To find the minimum spanning tree using Prim’s algorithm

PSEUDOCODE:

T = ∅;
U = { 1 };
while (U ≠ V)
let (u, v) be the lowest cost edge such that u ∈ U and v ∈ V - U;
T = T 𝖴 {(u, v)}
U = U 𝖴 {v}
The steps for implementing Prim's algorithm are as follows:
1. Initialize the minimum spanning tree with a vertex chosen at random.
2. Find all the edges that connect the tree to new vertices, find the minimum and add it to the tree
3. Keep repeating step 2 until we get a minimum spanning tree
PROGRAM:

#include<stdio.h>
#include<stdbool.h>
#define INF 9999999
// number of vertices in graph
#define V 5
// create a 2d array of size 5x5
//for adjacency matrix to represent graph
int G[V][V] = {
{0, 9, 75, 0, 0},
{9, 0, 95, 19, 42},
{75, 95, 0, 51, 66},
{0, 19, 51, 0, 31},
{0, 42, 66, 31, 0}};

int main() {
int no_edge; // number of edge
int mincost=0;
// create a array to track selected vertex
// selected will become true otherwise false
int selected[V];

// set selected false initially


memset(selected, false, sizeof(selected));

// set number of edge to 0


no_edge = 0;

// the number of egde in minimum spanning tree will


be

// always less than (V -1), where V is number ofvertices in


//graph
// choose 0th vertex and make it true
selected[0] = true;
int x; // row number
int y; // col number
// print for edge and weight
printf("Edge : Weight\n");
while (no_edge < V - 1) {
//For every vertex in the set S, find the all adjacent
vertices
// , calculate the distance from the vertex selected at
step 1.
// if the vertex is already in the set S, discard it
otherwise
//choose another vertex nearest to selected vertex at
step 1.
int min = INF;
x = 0;
y = 0;
for (int i = 0; i < V; i++) {
if (selected[i]) {
for (int j = 0; j < V; j++) {
if (!selected[j] && G[i][j]) { // not in selected
and there is an edge
if (min > G[i][j]) {
min = G[i][j];
x = i;
y = j;

}
}
}
}
}
printf("%d - %d : %d\n", x, y, G[x][y]);

selected[y] = true;
no_edge++;
mincost=mincost+min;
}
printf("Minimum cost is %d",mincost);
return 0;
}
Time Complexity Analysis:
Time Complexity
The time complexity of Prim's algorithm depends on the data structure used to represent the graph:
 Adjacency Matrix Representation:
o Finding Minimum Edge:
 The nested loops iterate through all vertices (V), checking edges for each vertex. This results in
a time complexity of O(V2) for finding the minimum edge.
o Total Algorithm Complexity:
 Since each of the V vertices can potentially connect with V-1 other vertices, the overall time
complexity of Prim's algorithm with an adjacency matrix representation is O(V2)
Space Complexity Analysis:
 Space Complexity:
o The space complexity primarily depends on the adjacency matrix G, which uses O(V2) space to store
the graph.
o Additional space is used for the selected array of size V, which tracks the vertices included in the MST.
Hence, the space complexity is O(V2+V), which simplifies to O(V2)
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the minimumspanningtree is found usingPrim’s algorithm.


[Link]: MINIMUM SPANNING TREE USING KRUSKAL’S ALGORITHM
DATE:

AIM:

To find the minimum spanning tree using Kruskal’s algorithm

PSEUDOCODE:

KRUSKAL(G):
A=∅
For each vertex v ∈ G.V:
MAKE-SET(v)
For each edge (u, v) ∈ G.E ordered by increasing order by weight(u, v):
if FIND-SET(u) ≠ FIND-SET(v):
A = A 𝖴 {(u, v)}
UNION(u, v)
return A
PROGRAM:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int i, j, k, a, b, u, v, n, ne = 1;
int min, mincost = 0, cost[9][9], parent[9];
int find(int);
int uni(int, int);
void main() {
printf("\n\tImplementation of Kruskal's Algorithm\n");
printf("\nEnter the no. of vertices:");
scanf("%d", & n);
printf("\nEnter the cost adjacency matrix:\n");
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
scanf("%d", & cost[i][j]);
if (cost[i][j] == 0)
cost[i][j] = 999;
}
}
printf("The edges of Minimum Cost Spanning Tree are\n");
while (ne < n) {
for (i = 1, min = 999; i <= n; i++) {
for (j = 1; j <= n; j++) {
if (cost[i][j] < min) {
min = cost[i][j];
a = u = i;
b = v = j;
}
}
}
u = find(u);
v = find(v);
if (uni(u, v)) {
printf("%d edge (%d,%d) =%d\n", ne++, a, b, min);
mincost += min;
}
cost[a][b] = cost[b][a] = 999;
}
printf("\n\tMinimum cost = %d\n", mincost);
getch();
}
int find(int i) {
while (parent[i])
i = parent[i];
return i;
}
int uni(int i, int j) {
if (i != j) {
parent[j] = i;
return 1;
}
return 0;
}

Time Complexity Analysis:


The time complexity of Kruskal's algorithm primarily depends on the sorting of edges and the disjoint-set
operations:
1. Sorting Edges:
o The program does not explicitly sort the edges, but it iterates through the entire adjacency matrix
(assuming nnn vertices), which is O(n2 ) This step is where the algorithm finds the minimum cost
edge repeatedly.
2. Disjoint-Set Operations:
o The find and uni functions perform operations on disjoint sets using path compression and union
by rank. The find operation has an amortized time complexity of O(α(n)), where α\alphaα is the
inverse Ackermann function (very slowly growing function). The uni operation (union by rank)
also has a time complexity of O(α(n)).
3. Overall Time Complexity:
o Considering these factors, the overall time complexity of Kruskal's algorithm is dominated by the
edge sorting step, which is O(n2 ). The disjoint-set operations add an additional factor of O(α(n)),
making the total time complexity O(n2 +m⋅α(n)), where m is the number of edges and n is the
number of vertices.
Space Complexity Analysis:
 Space Complexity:
o The space complexity is primarily due to the adjacency matrix cost, which uses O(n2 ) space.
o Additional space is used for the parent array of size n to track the parent of each vertex in the
disjoint-set structure.
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the minimum spanning tree is found using Kruskal’s algorithm.


[Link]: SINGLE-SOURCE SHORTEST PATH
DATE:

AIM:
To find the shortest path from a single source using Dijkstra’s Algorithm

PSEUDOCODE:

function dijkstra(G, S)
for each vertex V in G
distance[V] <- infinite
previous[V] <- NULL
If V != S, add V to Priority Queue Q
distance[S] <- 0

while Q IS NOT EMPTY


U <- Extract MIN from Q
for each unvisited neighbour V of U
tempDistance <- distance[U] + edge_weight(U, V)
if tempDistance < distance[V]
distance[V] <- tempDistance
previous[V] <- U
return distance[], previous[]
PROGRAM:

#include <stdio.h>
#include <conio.h>
#define infinity 9999
void dij(int n,int v,int cost[10][10],int dist[])
{
int i,u,count,w,flag[10],min;
for(i=1;i<=n;i++) f
lag[i]=0,dist[i]=cost[v][i];
count=2;
while(count<=n)
{
min=99;
for(w=1;w<=n;w++)
if(dist[w]<min && !flag[w])
min=dist[w],u=w; flag[u]=1; count++;
for(w=1;w<=n;w++)
if((dist[u]+cost[u][w]<dist[w]) && !flag[w])
dist[w]=dist[u]+cost[u][w];
}
}
void main()
{
int n,v,i,j,cost[10][10],dist[10];
clrscr();
printf("\n Enter the number of nodes:");
scanf("%d",&n);
printf("\n Enter the cost matrix:\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&cost[i][j]);
if(cost[i][j]==0) cost[i][j]=infinity;
}
printf("\n Enter the source matrix:");
scanf("%d",&v);
dij(n,v,cost,dist);
printf("\n Shortest path:\n");
for(i=1;i<=n;i++)
if(i!=v)
printf("%d->%d,cost=%d\n",v,i,dist[i]);
getch();
}
Dijkstra's algorithm, as implemented above, has a time complexity of O(n2)

1. Initialization (O(n)):
o Initializing the dist and flag arrays takes O(n) time, where nis the number of vertices.
2. Finding the Minimum Distance Vertex (O(n2))
o In each iteration of the while loop, we need to find the vertex with the minimum distance that
hasn't been included in the shortest path tree yet. This involves scanning all vertices, which takes
O(n)) time in the worst case.
o This process is repeated nnn times (once for each vertex), leading to a total of O(n)×O(n)= O(n2)
3. Updating the Distance Values O(n2)
o For each selected vertex u, we update the distance values of its adjacent vertices. In the worst
case, this can take O(n) time for each vertex u.
o Since we do this for n vertices, the total time for this step is also O(n)×O(n)= O(n2)

Thus, the overall time complexity of Dijkstra's algorithm using an adjacency matrix and simple
arrays is O(n2 )

Space Complexity

The space complexity of the algorithm is determined by the amount of memory used by the adjacency
matrix and the additional arrays.

1. Adjacency Matrix (O(n2)):


o The adjacency matrix cost is of size n×n is the number of vertices. This requires O(n2 )
space.
2. Distance and Flag Arrays (O(n)):
o The dist array stores the shortest path estimates from the source to each vertex, requiring
O(n) space.
o The flag array keeps track of whether a vertex is included in the shortest path tree, also
requiring O(n) space.
3. Other Variables (O(1)):
o Other variables such as i, j, u, v, count, min, etc., are constant in number and therefore
require O(1) space.

Combining these, the total space complexity is:

O(n2)+O(n)+O(1)=O(n2)
INPUT/OUTPUT:
Enter the number of nodes: 7
Enter the cost matrix
0 0 1 2 0 0 0
0 0 2 0 0 3 0
1 2 0 1 3 0 0
2 0 1 0 0 0 1
0 0 3 0 0 2 0
0 3 0 0 2 0 1
0 0 0 1 0 1 0

TERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:
Using Dijkstra algorithm the shortest path from a single source in the given cost matrix is found.
Dynamic Programming
Technique
Dynamic Programming (DP) is a method used in mathematics and computer science to solve complex problems
by breaking them down into simpler subproblems. By solving each subproblem only once and storing the results,
it avoids redundant computations, leading to more efficient solutions for a wide range of problems.

How Does Dynamic Programming (DP)Work?


Identify Subproblems: Divide the main problem into smaller, independent subproblems.
Store Solutions: Solve each subproblem and store the solution in a table or array.
Build Up Solutions: Use the stored solutions to build up the solution to the main problem.
Avoid Redundancy: By storing solutions, DP ensures that each subproblem is solved only once, reducing
computation time.
Common Algorithms that Use Dynamic Programming:
Longest Common Subsequence (LCS): Finds the longest common subsequence between two strings.
Shortest Path in a Graph: Finds the shortest path between two nodes in a graph.
Knapsack Problem: Determines the maximum value of items that can be placed in a knapsack with a given capacity.
Matrix Chain Multiplication: Optimizes the order of matrix multiplication to minimize the number of operations.
Fibonacci Sequence: Calculates the nth Fibonacci number.
[Link]: ALL PAIRS SHORTEST PATHS USING DYNAMIC PROGRAMMING
DATE: TECHNIQUE.

AIM:
To find the shortest path from all the vertices using Floyd-Warshall Algorithm (Dynamic Programming
Approach)

PSEUDOCODE:

n = no of vertices
A = matrix of dimension n*n
for k = 1 to n
for i = 1 to n
for j = 1 to n
Ak[i, j] = min (Ak-1[i, j], Ak-1[i, k] + Ak-1[k, j])
return A
PROGRAM:

// Floyd-Warshall Algorithm in C
#include <stdio.h>
// defining the number of vertices
#define nV 4

#define INF 999

void printMatrix(int matrix[][nV]);

// Implementing floyd warshall algorithm


void floydWarshall(int graph[][nV]) {
int matrix[nV][nV], i, j, k;

for (i = 0; i < nV; i++)


for (j = 0; j < nV; j++)
matrix[i][j] = graph[i][j];
// Adding vertices individually
for (k = 0; k < nV; k++) {
for (i = 0; i < nV; i++) {
for (j = 0; j < nV; j++) {
if (matrix[i][k] + matrix[k][j] < matrix[i][j])
matrix[i][j] = matrix[i][k] + matrix[k][j];
}
}
}
printMatrix(matrix);
}

void printMatrix(int matrix[][nV]) {


for (int i = 0; i < nV; i++) {
for (int j = 0; j < nV; j++) {
if (matrix[i][j] == INF)
printf("%4s", "INF");
else
printf("%4d", matrix[i][j]);
}
printf("\n");
}
}

int main() {
int graph[nV][nV] = {{0, 3, INF, 5},
{2, 0, INF, 4},
{INF, 1, 0, INF},
{INF, INF, 2, 0}};
floydWarshall(graph);
}
Time Complexity

The time complexity of the Floyd-Warshall algorithm can be analyzed by examining its triple nested loops.

for (k = 0; k < nV; k++) { // Outer loop runs n times


for (i = 0; i < nV; i++) { // Middle loop runs n times for each k
for (j = 0; j < nV; j++) // Inner loop runs n times for each i
{
// Constant time operation
if (matrix[i][k] != INF && matrix[k][j] != INF && matrix[i][k] +
matrix[k][j] < matrix[i][j])
matrix[i][j] = matrix[i][k] + matrix[k][j];
}
}
}

 Outer Loop (k): Runs n times where n is the number of vertices.


 Middle Loop (i): For each iteration of the outer loop, this loop runs n times.
 Inner Loop (j): For each iteration of the middle loop, this loop runs n times.

Since each loop runs n times, the total number of iterations of the innermost statement is:

n×n×n=n

Therefore, the time complexity of the Floyd-Warshall algorithm is:

O(n3)

This cubic time complexity indicates that the algorithm will take significantly longer to run as the number
of vertices increases, making it suitable for graphs with a relatively small number of vertices.

Space Complexity

The space complexity of the Floyd-Warshall algorithm primarily depends on the space required to store the
graph and the shortest path matrix.

1. Graph Representation:
o The input graph is typically represented as an adjacency matrix, which requires O(n2) space.
2. Shortest Path Matrix:
o The algorithm uses an additional 2D array (matrix) to store the shortest path distances. This also
requires O(n2)) space.
3. Auxiliary Space:
o The space for the loop control variables (i, j, k) and other variables (min) is insignificant compared
to the space required for the matrices.

Thus, the overall space complexity of the Floyd-Warshall algorithm is:

O(n2)
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Using Floyd-Warshall Algorithm the shortest path from all the vertices are found.
[Link]: TRAVELING SALESMAN PROBLEM USING DYNAMIC
DATE: PROGRAMMING

AIM:

To solve travelling salesman problem using dynamic programming

PSEUDOCODE:

Algorithm: Traveling-Salesman-Problem
C ({1}, 1) = 0
for s = 2 to n do
for all subsets S є {1, 2, 3, … , n} of size s and containing 1
C (S, 1) = ∞
for all j є S and j ≠ 1
C (S, j) = min {C (S – {j}, i) + d(i, j) for i є S and i ≠ j}
Return minj C ({1, 2, 3, …, n}, j) + d(j, i)
PROGRAM:

#include <stdio.h>
int matrix[25][25], visited_cities[10], limit, cost = 0;

int tsp(int c)
{
int count, nearest_city = 999;
int minimum = 999, temp;
for(count = 0; count < limit; count++)
{
if((matrix[c][count] != 0) && (visited_cities[count] == 0))
{
if(matrix[c][count] < minimum)
{
minimum = matrix[count][0] + matrix[c][count];
}
temp = matrix[c][count];
nearest_city = count;
}
}
if(minimum != 999)
{
cost = cost + temp;
}
return nearest_city;
}

void minimum_cost(int city)


{
int nearest_city;
visited_cities[city] = 1;
printf("%d ", city + 1);
nearest_city = tsp(city);
if(nearest_city == 999)
{
nearest_city = 0;
printf("%d", nearest_city + 1);
cost = cost + matrix[city][nearest_city];
return;
}
minimum_cost(nearest_city);
}

int main()
{
int i, j;
printf("Enter Total Number of Cities:\t");
scanf("%d", &limit);
printf("\nEnter Cost Matrix\n");
for(i = 0; i < limit; i++)
{
printf("\nEnter %d Elements in Row[%d]\n", limit, i + 1);
for(j = 0; j < limit; j++)
{
scanf("%d", &matrix[i][j]);
}
visited_cities[i] = 0;
}
printf("\nEntered Cost Matrix\n");
for(i = 0; i < limit; i++)
{
printf("\n");
for(j = 0; j < limit; j++)
{
printf("%d ", matrix[i][j]);
}
}
printf("\n\nPath:\t");
minimum_cost(0);
printf("\n\nMinimum Cost: \t");
printf("%d\n", cost);
return 0;
}
Time Complexity Analysis

1. Matrix Input:
o Reading the cost matrix: O(N 2 ) where NNN is the number of cities. This is because the program
iterates through each element of the matrix to read the input.
2. Greedy Algorithm (tsp function):
o Finding the nearest unvisited city: O(N) In the worst case, this involves checking each city to find
the minimum cost path from the current city.
3. Recursive Path Construction (minimum_cost function):
o The recursion depth in the minimum_cost function can go up to NNN, because in the worst case,
each city is visited exactly once.

Therefore, the overall time complexity of the algorithm is O(N2+N2)=O(N2)

Space Complexity Analysis:

1. Matrix and Additional Arrays:


o The space complexity primarily involves storing the cost matrix and additional arrays
(visited_cities, matrix), which collectively take O(N 2 ) space.
2. Recursive Stack:
o The space used by the recursive stack in the minimum_cost function is O(N)due to the depth of the
recursion.

Thus, the overall space complexity is O(N2+N)=O(N2).


INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:
Thus the Travelling salesman problem is solved using dynamic programming.
Backtracking Technique
Backtracking is a problem-solving algorithmic technique that involves finding a solution incrementally by trying
different options and undoing them if they lead to a dead end. It is commonly used in situations where you need
to explore multiple possibilities to solve a problem, like searching for a path in a maze or solving puzzles like
Sudoku. When a dead end is reached, the algorithm backtracks to the previous decision point and explores a
different path until a solution is found or all possibilities have been exhausted.

Applications of Backtracking
Creating smart bots to play Board Games such as Chess.
Solving mazes and puzzles such as N-Queen problem.
Network Routing and Congestion Control.
Decryption
Text Justification
[Link]: N-QUEEN PROBLEM OR 8 QUEEN
DATE: PROBLEM

AIM:
To solve N-queen problem using backtracking algorithm

PSEUDOCODE:

Place (k, i)
{
For j ← 1 to k - 1
do if (x [j] = i)
or (Abs x [j]) - i) = (Abs (j - k))
then return false;
return true;
}

N - Queens (k, n)
{
For i ← 1 to n
do if Place (k, i) then
{
x [k] ← i;
if (k ==n) then
write (x [1. ..n));
else
N - Queens (k + 1, n);
}
}
PROGRAM:

#include<stdio.h>
#define BOARD_SIZE 5
void displayChess(int chBoard[BOARD_SIZE][BOARD_SIZE]) {
for (int row = 0; row < BOARD_SIZE; row++) {
for (int col = 0; col < BOARD_SIZE; col++)
printf("%d ", chBoard[row][col]);
printf("\n");
}
}
int isQueenPlaceValid(int chBoard[BOARD_SIZE][BOARD_SIZE], int crntRow, int crntCol) {
// checking if queen is in the left or not
for (int i = 0; i < crntCol; i++)
if (chBoard[crntRow][i])
return 0;
for (int i = crntRow, j = crntCol; i >= 0 && j >= 0; i--, j--)
//checking if queen is in the left upper diagonal or not
if (chBoard[i][j])
return 0;
for (int i = crntRow, j = crntCol; j >= 0 && i < BOARD_SIZE; i++, j--)
//checking if queen is in the left lower diagonal or not
if (chBoard[i][j])
return 0;
return 1;
}
int solveProblem(int chBoard[BOARD_SIZE][BOARD_SIZE], int crntCol) {
//when N queens are placed successfully
if (crntCol >= BOARD_SIZE)
return 1;
// checking placement of queen is possible or not
for (int i = 0; i < BOARD_SIZE; i++) {
if (isQueenPlaceValid(chBoard, i, crntCol)) {
//if validate, place the queen at place (i, col)
chBoard[i][crntCol] = 1;
//Go for the other columns recursively

if (solveProblem(chBoard, crntCol + 1))


return 1;
//When no place is vacant remove that queen
chBoard[i][crntCol] = 0;
}
}
return 0;
}
int displaySolution() {
int chBoard[BOARD_SIZE][BOARD_SIZE];
for(int i = 0; i < BOARD_SIZE; i++)
for(int j = 0; j < BOARD_SIZE; j++)
//set all elements to 0
chBoard[i][j] = 0;
//starting from 0th column
if (solveProblem(chBoard, 0) == 0) {

printf("Solution does not exist");

return 0;
displayChess(chBoard);
return 1;
}
int main() {
displaySolution();
return 0;
}

 Time Complexity: The time complexity of the solveProblem function can be expressed as O(N!), where
N is the size of the chessboard (BOARD_SIZE). This is because:
o In the worst case, the function recursively tries all possible combinations of queen placements.
o The function explores N choices for the first queen, N-1 choices for the second queen, and so on.
o Therefore, the total number of recursive calls (and hence operations) can be estimated as N * (N-1) * (N-2)
* ... * 1 = N!.
 Space Complexity: The space complexity primarily comes from the space used by the chBoard array:
o chBoard: Requires O(N2) space to store the NxN chessboard.
o Recursive Stack: The recursive calls of solveProblem can go up to depth N. Therefore, the space
complexity due to recursion is O(N).
o Overall, the space complexity is O(N2+ N) = O(N2), dominated by the chessboard array.
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25
RESULT:

Thus the N-queen problem is solved using backtracking algorithm.


[Link]: SUM OF SUBSETS
DATE:
AIM:
To find the subset of a set is such a way that the element of the given subset sum up to a given
number K

PSEUDOCODE:

function subset_sum(list[],sum, starting_index, target_sum)


begin
if( target_sum == sum )

subset_countsubset_count+1;
if(starting_index < [Link])
subset_sum(list, sum - list[starting_index-1], starting_index, target_sum);
else

for i=strating_index to [Link] do

subset_sum(list, sum + list[i], i + 1, target_sum);


end loop
end if

end
PROGRAM:

#include <stdio.h>
#include <stdbool.h>
void printSubset(int subset[], int size) {
printf("Subset: { ");
for (int i = 0; i < size; i++) {
printf("%d ", subset[i]);
}
printf("}\n");
}
void sumOfSubsetsUtil(int weights[], int targetSum, int n, int subset[], int subsetSize, int
sum, int index) {
if (sum == targetSum) {
printSubset(subset, subsetSize);
return;
}
for (int i = index; i < n; i++) {
if (sum + weights[i] <= targetSum) {
subset[subsetSize] = weights[i];
sumOfSubsetsUtil(weights, targetSum, n, subset, subsetSize + 1, sum +
weights[i], i + 1);
}
}
}

void sumOfSubsets(int weights[], int targetSum, int n) {


int subset[n];
sumOfSubsetsUtil(weights, targetSum, n, subset, 0, 0, 0);
}

int main() {
int n, targetSum;
printf("Enter the number of elements: ");
scanf("%d", &n);
int weights[n];
printf("Enter the elements: ");
for (int i = 0; i < n; i++) {
scanf("%d", &weights[i]);
} printf("Enter the target sum: ");
scanf("%d", &targetSum);
sumOfSubsets(weights, targetSum, n);
return 0;
}

Time Complexity Analysis:


 Recursive Calls: The function uses recursion to explore all possible combinations of elements.
 Backtracking Mechanism:
 For each element in weights[], the function decides whether to include it in the current subset or
not.
 The recursion explores two possibilities for each element: include it or exclude it.
 Therefore, the time complexity is exponential, O(2n), where n is the number of elements in
weights[].
 This is because each element has 2 choices (include or exclude) and there are n elements.
Space Complexity Analysis:
 Space Usage:
 subset[] array: O(n) space to store the current subset.
 Recursive Stack
 Depth of recursion is at most n (when considering all elements).
 Each recursive call consumes a certain amount of space on the stack
 Therefore, the space complexity due to recursion is O(n).
 Overall Space Complexity: O(n) due to the subset[] array and O(n) due to recursion,
leading to a total of O(n + n) = O(n).
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the subset of a set is found by using the element of the given subset that sum up to
a given Number k.
Branch-and-Bound
Technique
Branch and bound algorithms are used to find the optimal solution for combinatory, discrete, and general mathematical
optimization problems.
A branch and bound algorithm provides an optimal solution to an NP-Hard problem by exploring the entire search space.
Through the exploration of the entire search space, a branch and bound algorithm identify possible candidates for solutions
step-by-step.
Basic Concepts of Branch and Bound:
▸ Generation of a state space tree:
As in the case of backtracking, B&B generates a state space tree to efficiently search the solution space of a given problem
[Link] B&B, all children of an E-node in a state space tree are produced before any live node gets converted in an E-
node. Thus, the E-node remains an E-node until i becomes a dead node.
Evaluation of a candidate solution:
Unlike backtracking, B&B needs additional factors evaluate a candidate solution:
A way to assign a bound on the best values of the given criterion functions to each node in a state space tree: It is produced
by the addition of further omponents to the partial solution given by that node.
The best values of a given criterion function obtained so far: It describes the upper bound for the maximization problem and
the lower bound for the minimization problem.
A feasible solution is defined by the problem states that satisfy all the given constraints.
An optimal solution is a feasible solution, which produces the best value of a given objective function.
Bounding function :
It optimizes the search for a solution vector in the solution space of a given problem instance. It is a heuristic function that
evaluates the lower and upper bounds on the possible solutions at each node. The bound values are used to search the partial
solutions leading to an optimal solution. If a node does not produce a solution better than the best solution obtained thus far,
then it is abandoned without further [Link] algorithm then branches to another path to get a better solution. The
desired solution to the problem is the value of the best solution produced so far.
Applications of Branch and Bound:
Combinatorial Optimization: Branch and Bound is widely used in solving combinatorial optimization problems such as the
Traveling Salesman Problem (TSP), Knapsack Problem, and Job Scheduling.
Constraint Satisfaction Problems: Branch and Bound can efficiently handle constraint satisfaction problems by systematically
exploring the search space and pruning branches based on constraints.
Resource Allocation: It’s applied in scenarios like resource allocation where resources need to be distributed optimally among
competing demands.
[Link]: TRAVELLING SALESMAN PROBLEM USING BRANCH AND BOUND
DATE:

AIM:
To solve the traveling salesman problem using branch and bound algorithm

PSEUDOCODE:
′ ′
Require: set Q of nodes (Y, N, S, c ) ordered by increasing c ∈R
Let Q = {( ø, ø, ø, −∞)}
while Q /= ø do

Let α = (Y, N, S, c′) = argminc ′ Q; let Q = Q z {α}

if φ(α) = 1 then
Let R = lowerBound(α)
if d(R) < d(S) then if τ ( R) =
0 then
if Y 𝖴N /= A then
choose a ∈A z (Y 𝖴N )
Let β = (Y {a}, N, S, d(R)); let γ = (Y, N 𝖴{a}, S, d(R))
Let Q = Q 𝖴{β, γ}
end if
else
Let S = R
end if end if
end if
end while return S
PROGRAM:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define N 4 // Number of cities

// Function to find the minimum cost edge connected to the node


int findMin(int adj[N][N], int i, int n) {
int min = INT_MAX;
for (int k = 0; k < n; k++) {
if (adj[i][k] < min && i != k)
min = adj[i][k];
}
return min;
}

// Function to calculate the lower bound of the path


int calculateBound(int adj[N][N], int path[], int level, int n) {
int bound = 0;
for (int i = 0; i < level; i++) {
bound += adj[path[i]][path[i+1]];
}
for (int i = level; i < n; i++) {
bound += findMin(adj, path[i], n);
}
return bound;
}

// Function to copy temporary solution to the final solution


void copyToFinal(int curr_path[], int n, int final_path[]) {
for (int i = 0; i < n; i++) {
final_path[i] = curr_path[i];
}
final_path[n] = curr_path[0];
}

// Recursive function to solve TSP using Branch and Bound


void TSPRec(int adj[N][N], int curr_bound, int curr_weight, int level, int curr_path[], int visited[], int final_path[], int
*final_res, int n) {
if (level == n) {
if (adj[curr_path[level-1]][curr_path[0]] != 0) {
int curr_res = curr_weight + adj[curr_path[level-1]][curr_path[0]];
if (curr_res < *final_res) {
copyToFinal(curr_path, n, final_path);
*final_res = curr_res;
}
}
return;
}

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


if (adj[curr_path[level-1]][i] != 0 && visited[i] == 0) {
int temp = curr_bound;
curr_weight += adj[curr_path[level-1]][i];
if (level == 1) {
curr_bound -= ((findMin(adj, curr_path[level-1], n) + findMin(adj, i, n)) / 2);
} else {
curr_bound -= ((findMin(adj, curr_path[level-1], n) + findMin(adj, i, n)) / 2);
}

if (curr_bound + curr_weight < *final_res) {


curr_path[level] = i;
visited[i] = 1;

TSPRec(adj, curr_bound, curr_weight, level+1, curr_path, visited, final_path, final_res, n);


}

curr_weight -= adj[curr_path[level-1]][i];
curr_bound = temp;

for (int j = 0; j < n; j++) {


visited[j] = 0;
}
for (int j = 0; j <= level-1; j++) {
visited[curr_path[j]] = 1;
}
}
}
}

// Function to solve TSP using Branch and Bound


void TSP(int adj[N][N], int n) {
int curr_path[N+1];
int visited[N];
int final_path[N+1];
int final_res = INT_MAX;

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


visited[i] = 0;
curr_path[i] = -1;
}

int curr_bound = 0;
for (int i = 0; i < n; i++) {
curr_bound += (findMin(adj, i, n) + findMin(adj, i, n));
}
curr_bound = (curr_bound & 1) ? curr_bound/2 + 1 : curr_bound/2;

visited[0] = 1;
curr_path[0] = 0;
TSPRec(adj, curr_bound, 0, 1, curr_path, visited, final_path, &final_res, n);
printf("Minimum cost: %d\n", final_res);
printf("Path: ");
for (int i = 0; i <= n; i++) {
printf("%d ", final_path[i]);
}
printf("\n");
}
int main()
{
int adj[N][N] = {
{0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};

TSP(adj, N);

return 0;
}
Time Complexity Analysis:
1. Initial Setup (TSP function):
o Calculating curr_bound: This involves finding the minimum edges connected to each node, which is
O(N2), where NNN is the number of cities.
o Initial setup of arrays: Setting up arrays like curr_path and visited takes O(N)
2. Recursive Function (TSPRec function):
o The recursive function TSPRec is called recursively to explore all possible paths. The number of recursive
calls in the worst case is N! (factorial of N), because the algorithm explores all permutations of cities.
o Within each recursive call:
 Finding minimum edges: findMin function is called twice for each city, contributing O(N) each
time.
 Updating curr_bound: This operation is O(1).
 Checking conditions and updating paths: These operations are O(1) each.
 Resetting visited array: This operation is O(N).
Therefore, each call to TSPRec has a time complexity of O(N2).
3. Final Output:
o Printing the final path and minimum cost takes O(N).
Combining these, the overall time complexity of the algorithm is dominated by the recursive calls, which is O(N×N!+N2).
Space Complexity Analysis:
1. Arrays and Matrices:
o adj matrix: Takes O(N2) space.
o visited, curr_path, final_path: Each takes O(N) space.
o Other variables: Take constant space, O(1)
2. Recursive Stack:
o The depth of recursion can go up to NNN, so the space complexity due to recursion is O(N)
Therefore, the overall space complexity is O(N 2)
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:
Thus The traveling salesman problem is solved using branch and bound algorithm.
Content Beyond the Syllabus
[Link]: Telecommunication Network Design
DATE:

Description
Consider a real time scenario, where the network designers need to connect five cities with the least
cost in terms of laying down optical fiber cables. The cities and the costs (in units) of laying cables between them are
represented in a weighted graph.
Here is the adjacency matrix for the graph:

A B C D

A 0 2 3 0

B 2 0 4 1

C 3 4 0 5

D 0 1 5 0

E 0 0 6 7

PSEUDOCODE:
Function kruskalAlgo():
For i from 0 to n-1:
For j from 0 to n-1:
If Graph[i][j] is not 0 and i < j:
Set [Link][elist.n].u = i
Set [Link][elist.n].v = j
Set [Link][elist.n].w =Graph[i][j]
Increment elist.n by 1
For i from 0 to n-1:
Set belongs[i] = i
Set spanlist.n = 0
For i from 0 to elist.n-1:
Set cno1 = find(belongs, [Link][i].u)
Set cno2 = find(belongs, [Link][i].v)
If cno1!= cno2:
Set [Link][spanlist.n] = [Link][i]
Increment spanlist.n by 1
applyUnion(belongs, cno1, cno2)
Return belongs[vertexno]
Function applyUnion(belongs, c1, c2):
For i from 0 to n-1:
If belongs[i] == c2:
Set belongs[i] = c
Function sort():
For i from 1 to elist.n-1:
For j from 0 to elist.n-2:
If [Link][j].w > [Link][j + 1].w:
Set temp = [Link][j]
Set [Link][j] = [Link][j + 1]
Set [Link][j + 1] = temp

Function print():
For i from 0 to spanlist.n-1:
Print [Link][i].u, [Link][i].v, and [Link][i].w
Add [Link][i].w to cost
Print the total cost of the spanning tree as cost
PROGRAM:
#include <stdio.h>
# define MAX 30
typedef struct edge {
int u, v, w;
} edge;
typedef struct edge_list {
edge data[MAX];
int n;
} edge_list;
edge_list elist;
int Graph[MAX][MAX], n;
edge_list spanlist;
void kruskalAlgo();
int find(int belongs[], int vertexno);
void applyUnion(int belongs[], int c1, int c2);
void sort();
void print();
// Applying Krushkal Algo
void kruskalAlgo() {
int belongs[MAX], i, j, cno1, cno2;
elist.n = 0;
for (i = 1; i < n; i++)
for (j = 0; j < i; j++) {
if (Graph[i][j] != 0) {
[Link][elist.n].u = i;
[Link][elist.n].v = j;
[Link][elist.n].w = Graph[i][j];
elist.n++;
}
}
}
sort();
for (i = 0; i < n; i++)
belongs[i] = i;
spanlist.n = 0;
for (i = 0; i < elist.n; i++) {
cno1 = find(belongs, [Link][i].u);
cno2 = find(belongs, [Link][i].v);
if (cno1 != cno2) {
[Link][spanlist.n] = [Link][i];
spanlist.n = spanlist.n + 1;
applyUnion(belongs, cno1, cno2);
}
}}
int find(int belongs[], int vertexno) {
return (belongs[vertexno]);
}
void applyUnion(int belongs[], int c1, int c2) {
int i;
for (i = 0; i < n; i++)
if (belongs[i] == c2)
belongs[i] = c1;}
void sort() {
int i, j;

edge temp;
for (i = 1; i < elist.n; i++)
for (j = 0; j < elist.n - 1; j++)
if ([Link][j].w > [Link][j + 1].w) {
temp = [Link][j];
[Link][j] = [Link][j + 1];
[Link][j + 1] = temp;
}
}
void print() {
int i, cost = 0;
for (i = 0; i < spanlist.n; i++) {
printf("\n%d - %d : %d", [Link][i].u, [Link][i].v, [Link][i].w);
cost = cost + [Link][i].w;
}
printf("\nSpanning tree cost: %d", cost);
}
int main() {
int i, j, total_cost,n;
n = 6;
Graph[0][0] = 0;
Graph[0][1] = 4;
Graph[0][2] = 4;
Graph[0][3] = 0;
Graph[0][4] = 0;
Graph[1][0] = 4;
Graph[1][1] = 0;
Graph[1][2] = 2;
Graph[1][3] = 0;
Graph[1][4] = 0;
Graph[2][0] = 4;
Graph[2][1] = 2;
Graph[2][2] = 0;
Graph[2][3] = 3;
Graph[2][4] = 4;
Graph[3][0] = 0;
Graph[3][1] = 0;
Graph[3][2] = 3;
Graph[3][3] = 0;
Graph[3][4] = 3;
Graph[4][0] = 0;
Graph[4][1] = 0;
Graph[4][2] = 4;
Graph[4][3] = 4;
Graph[4][4] = 4;
Graph[5][0] = 0;
Graph[5][1] = 0;
Graph[5][2] = 2;
Graph[5][3] = 0;
Graph[5][4] = 3;
kruskalAlgo();
print();}
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

The cities are efficiently connected with a total cost of 14 units, using the least expensive
routes to ensure optimal network design.
[Link]: Grid-Based Robotic Path Planning Using
DATE: Dynamic Programming

AIM:
Consider a grid-world where an agent needs to find the shortest path from a start position to a goal
position. The agent can move in four directions (up, down, left, right) and each movement has a cost
associated with it.

PSEUDOCODE:

Define Constants
ROWS = 5
COLS = 5
INF = Infinity // Represents a very large number
Function min(a, b)
If a < b
Return a
Else
Return b
End If
End Function
Function shortestPath(grid, startX, startY, goalX, goalY)
Declare dp[ROWS][COLS] // DP table to store minimum cost to reach each cell b. Initialize DP table with INF
. For i <- 0 to ROWS-1
- For j <- 0 to COLS-1 –
dp[i][j] = INF

dp[startX][startY] = grid[startX][startY]

For i <- startX to goalX –


For j <- startY to goalY –
If i > startX or j > startY –
If i > startX - dp[i][j] = min(dp[i][j], dp[i-1][j] + grid[i][j]) –
End If –
If j > startY –
dp[i][j] = min(dp[i][j], dp[i][j-1] + grid[i][j])

Return dp[goalX][goalY]
PROGRAM:

#include <stdio.h>
#include <limits.h>
#define ROWS 5
#define COLS 5
#define INF INT_MAX
int min(int a, int b) {
return (a < b) ? a : b;
}
// Function to find the shortest path from start to goal in a grid
int shortestPath(int grid[ROWS][COLS], int startX, int startY, int goalX, int goalY) {
// DP table to store minimum cost to reach each cell
int dp[ROWS][COLS];

// Initialize DP table with infinity


for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLS; ++j) {
dp[i][j] = INF;
}
}

// Cost to reach the starting cell is the cost of the starting cell itself
dp[startX][startY] = grid[startX][startY];

// Fill the DP table


for (int i = startX; i <= goalX; ++i) {
for (int j = startY; j <= goalY; ++j) {
if (i > startX || j > startY) {
if (i > startX) {
dp[i][j] = min(dp[i][j], dp[i-1][j] + grid[i][j]);
}
if (j > startY) {
dp[i][j] = min(dp[i][j], dp[i][j-1] + grid[i][j]);
}
}
}
}

// Return the minimum cost to reach the goal cell


return dp[goalX][goalY];
}

int main() {
int grid[ROWS][COLS] = {
{3, 2, 8, 6, 4},
{6, 7, 3, 9, 2},
{5, 1, 5, 2, 7},
{8, 4, 1, 3, 4},
{4, 3, 2, 1, 9}
};
int startX = 0, startY = 0;
int goalX = ROWS - 1, goalY = COLS - 1;

int minCost = shortestPath(grid, startX, startY, goalX, goalY);

printf("Minimum cost to reach from (%d, %d) to (%d, %d) is: %d\n", startX, startY, goalX, goalY, minCost);

return 0;
}
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

The minimum cost to travel from the starting position (0, 0) to the goal position (4, 4) in the grid is 30. This
represents the least amount of cost incurred while moving through the specified grid cells.
[Link]: Sudoku Solver
DATE:

Objective: Solve a given 9x9 Sudoku puzzle using backtracking.


Tasks:
1. Implement a Sudoku solver using backtracking.
2. Read an input Sudoku puzzle from a file or user input.
3. Display the solved Sudoku grid.

PSEUDOCODE:
Function printGrid(grid)
For row <- 0 to N-1
For col <- 0 to N-1
Print grid[row][col] + " "

Function isSafe(grid, row, col, num)


For x <- 0 to N-1
If grid[row][x] == num
Return false
End For
For x <- 0 to N-1
If grid[x][col] == num
Return false

Function findEmptyCell(grid, row, col)


For row <- 0 to N-1
For col <- 0 to N-1 –
If grid[row][col] == 0 –
Return true

Function solveSudoku(grid)
Declare row, col
If findEmptyCell(grid, row, col) == false
Return true

For num <- 1 to 9


If isSafe(grid, row, col, num) - grid[row][col] <- num // Place num –
If solveSudoku(grid) == true –
Return true // Solved –
grid[row][col] <- 0
Program:

#include <stdio.h>
#include <stdbool.h>

#define N 9

// Function to print the Sudoku grid


void printGrid(int grid[N][N]) {
for (int row = 0; row < N; row++) {
for (int col = 0; col < N; col++) {
printf("%d ", grid[row][col]);
}
printf("\n");
}
}

// Function to check if it is safe to place a number in the given cell


bool isSafe(int grid[N][N], int row, int col, int num) {
// Check if the number is not already present in the current row
for (int x = 0; x < N; x++) {
if (grid[row][x] == num) {
return false;
}
}

// Check if the number is not already present in the current column


for (int x = 0; x < N; x++) {
if (grid[x][col] == num) {
return false;
}
}

// Check if the number is not already present in the current 3x3 box
int startRow = row - row % 3, startCol = col - col % 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (grid[i + startRow][j + startCol] == num) {
return false;
}
}
}

return true;
}
// Function to find an empty cell in the grid
bool findEmptyCell(int grid[N][N], int *row, int *col) {
for (*row = 0; *row < N; (*row)++) {
for (*col = 0; *col < N; (*col)++) {
if (grid[*row][*col] == 0) {
return true;

}
}
return false;
}

// Function to solve the Sudoku puzzle using backtracking


bool solveSudoku(int grid[N][N]) {
int row, col;

// If there is no empty cell, we are done


if (!findEmptyCell(grid, &row, &col)) {
return true;
}

// Try numbers from 1 to 9 in the current empty cell


for (int num = 1; num <= 9; num++) {
if (isSafe(grid, row, col, num)) {
grid[row][col] = num;

// Recursively try to solve the rest of the grid


if (solveSudoku(grid)) {
return true;
}

// If the current number does not lead to a solution, undo the move
grid[row][col] = 0;
}
}

// Trigger backtracking
return false;
}

// Driver code
int main() {
int grid[N][N] = {
{5, 3, 0, 0, 7, 0, 0, 0, 0},
{6, 0, 0, 1, 9, 5, 0, 0, 0},
{0, 9, 8, 0, 0, 0, 0, 6, 0},
{8, 0, 0, 0, 6, 0, 0, 0, 3},
{4, 0, 0, 8, 0, 3, 0, 0, 1},
{7, 0, 0, 0, 2, 0, 0, 0, 6},
{0, 6, 0, 0, 0, 0, 2, 8, 0},
{0, 0, 0, 4, 1, 9, 0, 0, 5},
{0, 0, 0, 0, 8, 0, 0, 7, 9}
};
if (solveSudoku(grid) == true) {
printGrid(grid);
} else {
printf("No solution exists\n");
}
return 0;
}
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:

Thus the traveling salesman problem is solved using branch and bound algorithm.
[Link]: Vehicle Routing Problem
DATE:

Problem Description:
 We have a set of customers with known demands.
 A fleet of vehicles, each with a maximum capacity.
 A single depot where all vehicles start and end.
 The goal is to minimize the total distance traveled while servicing all customers without exceeding
vehicle capacities.
This example will use a simplified problem with a small number of customers and vehicles.

PSEUDOCODE:

Function CalculateCost(Array route)


cost <- 0
For i <- 1 to numLocations - 1
cost <- cost + distances[route[i-1]][route[i]]
cost <- cost + distances[route[numLocations-1]][route[0]] // Return to depot
Return cost
Function BranchAndBound(Array route, Array visited, int level)
If level == numLocations
cost <- CalculateCost(route)
If cost < bestCost
bestCost <- cost
bestRoute <- route
EndIf
Return
EndIf
For i <- 1 to numLocations - 1
If visited[i] == false
visited[i] <- true
route[level] <- i
BranchAndBound(route, visited, level + 1)
visited[i] <- false // Backtrack
EndIf
EndFor
PROGRAM:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define N 4 // Number of customers + 1 depot
#define K 2 // Number of vehicles
#define INF INT_MAX
// Structure to represent a vehicle
typedef struct {
int capacity;
int load;
int position;
} Vehicle;
// Structure to represent the problem instance
typedef struct {
int distances[N][N];
int demands[N];
Vehicle vehicles[K];
int best_cost;
int best_route[N];
} VRPInstance;
// Function to initialize the VRP instance
void initializeVRP(VRPInstance *vrp) {
// Example distances (symmetric matrix)
int distances[N][N] = {
{0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};
// Example demands
int demands[N] = {0, 10, 15, 10}; // Depot has 0 demand
// Example vehicle capacities
for (int i = 0; i < K; i++) {
vrp->vehicles[i].capacity = 20;
vrp->vehicles[i].load = 0;
vrp->vehicles[i].position = 0; // All start at the depot
}
// Copy the data to the VRP instance
for (int i = 0; i < N; i++) {

for (int j = 0; j < N; j++) {


vrp->distances[i][j] = distances[i][j];
}
vrp->demands[i] = demands[i];
}
vrp->best_cost = INF;
}
// Function to calculate the cost of the current route
int calculateCost(VRPInstance *vrp, int route[N]) {
int cost = 0;
for (int i = 0; i < N - 1; i++) {
cost += vrp->distances[route[i]][route[i + 1]];
}
cost += vrp->distances[route[N - 1]][route[0]]; // Return to depot
return cost;
}

// Recursive function to implement the Branch and Bound algorithm


void branchAndBound(VRPInstance *vrp, int route[N], int visited[N], int level) {
if (level == N) {
int cost = calculateCost(vrp, route);
if (cost < vrp->best_cost) {
vrp->best_cost = cost;
for (int i = 0; i < N; i++) {
vrp->best_route[i] = route[i];
}
}
return;
}

for (int i = 1; i < N; i++) {


if (!visited[i]) {
visited[i] = 1;
route[level] = i;
branchAndBound(vrp, route, visited, level + 1);
visited[i] = 0;
}
}
}

int main() {
VRPInstance vrp;
initializeVRP(&vrp);

int route[N] = {0}; // Start from the depot


int visited[N] = {0};
visited[0] = 1; // Depot is visited

branchAndBound(&vrp, route, visited, 1);

printf("Best cost: %d\n", vrp.best_cost);


printf("Best route: ");
for (int i = 0; i < N; i++) {
printf("%d ", vrp.best_route[i]);
}
printf("\n");

return 0;
}
INPUT/OUTPUT:

CRITERIA [Link] MARKS OBTAINED


AIM & ALGORITHM 5
EXECUTION & OUTPUT 10
VIVA 10
TOTAL 25

RESULT:
The minimum total distance traveled to service all customers using the vehicles is 60 units. The optimal
route starts and ends at the depot, visiting the customers in the order: Depot → Customer 1 → Customer 3 →
Customer 2  Depot
[Link] [Link]

You might also like