0% found this document useful (0 votes)
19 views75 pages

DAA Lab: Matrix Multiplication & Algorithms

The document outlines various algorithms implemented in Python, including recursive and non-recursive algorithms, Strassen’s Matrix Multiplication, topological sorting, and heap sort. Each section includes the aim, algorithm steps, and program code, along with expected outputs and performance records. The results indicate successful implementation and verification of each algorithm.

Uploaded by

tamilarasusettu4
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)
19 views75 pages

DAA Lab: Matrix Multiplication & Algorithms

The document outlines various algorithms implemented in Python, including recursive and non-recursive algorithms, Strassen’s Matrix Multiplication, topological sorting, and heap sort. Each section includes the aim, algorithm steps, and program code, along with expected outputs and performance records. The results indicate successful implementation and verification of each algorithm.

Uploaded by

tamilarasusettu4
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

1

DATE: IMPLEMENT RECURSIVE AND NON-


RECURSIVE ALGORITHM AND STUDY
[Link] THE ORDER OF GROWTH
FROM log2n to n!

Aim:
To implement recursive and non-recursive algorithm and study the order of growth from
log2nto n! .

(A) Recursive Algorithm

(Tower of Hanoi)Algorithm:

Step 1 : Start with a function called tower_of_hanoi(n, from_rod, to_rod, aux_rod) which
takes 3 rods
and the number of disks as input.

Step 2 : If the number of disks is 1, move the disk from the from_rod to the to_rod.

Step 3 : Else, move the top n-1 disks from the from_rod to the aux_rod using the to_rod as
the auxiliaryrod.

Step 4 : move the nth disk from the from_rod to the to_rod

Step 5 : move the n-1 disks from the aux_rod to the to_rod using the from_rod as the
auxiliary rod.

Step 6 : End the function

2
Program:
# Python 3 program to
# find log(n) using

Recursiondef Log2n(n):

return 1 + Log2n(n / 2) if (n > 1) else 0

# Driver
coden = 32
print(Log2n(n))
n=3

Output:
5

3
(B) Non-Recursive Algorithm

(Finding sum elements in a array)Algorithm:

Step 1: Start with a function called sum_of_elements(arr) which takes an array as input.

Step 2: Create a variable called 'result' and set it to 0

Step 3: Use a for loop to iterate through all elements

in the array

Step 4: In each iteration, add the current element to

the result

Step 5: Return the result

Step 6: End the function

Program:

def
sum_of_elements(arr
):result = 0
for element in arr:
result += element
return result

arr = [1,2,3,4,5]
print(sum_of_elements(arr))

output:
15

4
Performance 25
Record 15
Viva 10
Total 50

(a)Result :

Thus the Recursive algorithm and study the order of growth from log2n to n! has
been implemented output verified and

(b) Result :

Thus the Non-recursive algorithm and study the order of growth from log2n to n! has
implemented successfully and output was verified

5
DATE: DIVIDE AND CONQUER - STRASSEN’S
MATRIX MULTIPLICATION
[Link]

Aim:
To implement Divide and Conquer algorithm using Strassen’s Matrix Multiplication.

Algorithm:

Step 1: Start with a function called strassen(A, B) which takes two matrices A and B as
input.

Step 2: Divide each matrix into 4 sub-matrices (A11, A12, A21, A22, B11, B12, B21, B22)

Step 3: Perform the following 7 matrix multiplications: S1 = B12 - B22 S2 = A11 +


A12 S3 = A21 + A22S4 = B21 - B11 S5 = A11 + A22 S6 = B11 + B22 S7 = A12 -
A22

Step 4: Calculate the following 4 matrix: P1 = A11 * S1 P2 = S2 * B22 P3 = S3 * B11 P4 =


A22 * S4

Step 5: Calculate the following 4 matrix: C11 = P1 + P2 C12 = P5 + P4 C21 = P3 + P4 C22


=P1 + P3 - P2
+ P6

Step 6: Combine the 4 matrices (C11, C12, C21, C22) to form the result matrix C.

Step 7: Return the matrix C

Step 8: End the function

6
Program:
# Python program to find the resultant
# product matrix for a given pair of matrices
# using Divide and Conquer Approach

ROW_1 = 4
COL_1 = 4
ROW_2 = 4
COL_2 = 4

#Function to print the matrix


def printMat(a, r, c):
for i in range(r):
for j in range(c):
print(a[i][j], end = " ")

print()
print()

#Function to print the matrix


def printt(display, matrix, start_row, start_column, end_row,end_column):
print(display + " =>\n")
for i in range(start_row, end_row+1):
for j in range(start_column, end_column+1):
print(matrix[i][j], end=" ")
print()
print()

#Function to add two matrices


def add_matrix(matrix_A, matrix_B, matrix_C, split_index):
for i in range(split_index):
for j in range(split_index):
matrix_C[i][j] = matrix_A[i][j] + matrix_B[i][j]

7
#Function to initialize matrix with zeros
def initWithZeros(a, r, c):
for i in range(r):
for j in range(c):
a[i][j] = 0

#Function to multiply two matrices


def multiply_matrix(matrix_A, matrix_B):
col_1 = len(matrix_A[0])
row_1 = len(matrix_A)
col_2 = len(matrix_B[0])
row_2 = len(matrix_B)

if (col_1 != row_2):
print("\nError: The number of columns in Matrix A must be equal to the number of
rows in Matrix B\n")
return 0

result_matrix_row = [0] * col_2


result_matrix = [[0 for x in range(col_2)] for y in range(row_1)]

if (col_1 == 1):

result_matrix[0][0] = matrix_A[0][0] * matrix_B[0][0]

else:

split_index = col_1 // 2

row_vector = [0] * split_index


result_matrix_00 = [[0 for x in range(split_index)] for y in range(split_index)]
result_matrix_01 = [[0 for x in range(split_index)] for y in range(split_index)]
result_matrix_10 = [[0 for x in range(split_index)] for y in range(split_index)]
result_matrix_11 = [[0 for x in range(split_index)] for y in range(split_index)]

8
a00 = [[0 for x in range(split_index)] for y in range(split_index)]
a01 = [[0 for x in range(split_index)] for y in range(split_index)]
a10 = [[0 for x in range(split_index)] for y in range(split_index)]
a11 = [[0 for x in range(split_index)] for y in range(split_index)]
b00 = [[0 for x in range(split_index)] for y in range(split_index)]
b01 = [[0 for x in range(split_index)] for y in range(split_index)]
b10 = [[0 for x in range(split_index)] for y in range(split_index)]
b11 = [[0 for x in range(split_index)] for y in range(split_index)]

for i in range(split_index):
for j in range(split_index):
a00[i][j] = matrix_A[i][j]
a01[i][j] = matrix_A[i][j + split_index]
a10[i][j] = matrix_A[split_index + i][j]
a11[i][j] = matrix_A[i + split_index][j + split_index]
b00[i][j] = matrix_B[i][j]
b01[i][j] = matrix_B[i][j + split_index]
b10[i][j] = matrix_B[split_index + i][j]
b11[i][j] = matrix_B[i + split_index][j + split_index]

add_matrix(multiply_matrix(a00, b00),multiply_matrix(a01,
b10),result_matrix_00, split_index)
add_matrix(multiply_matrix(a00, b01),multiply_matrix(a01,
b11),result_matrix_01, split_index)
add_matrix(multiply_matrix(a10, b00),multiply_matrix(a11,
b10),result_matrix_10, split_index)
add_matrix(multiply_matrix(a10, b01),multiply_matrix(a11,
b11),result_matrix_11, split_index)

for i in range(split_index):
for j in range(split_index):
result_matrix[i][j] = result_matrix_00[i][j]
result_matrix[i][j + split_index] = result_matrix_01[i][j]
result_matrix[split_index + i][j] = result_matrix_10[i][j]
result_matrix[i + split_index][j + split_index] = result_matrix_11[i][j]

return result_matrix

# Driver Code
matrix_A = [ [1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[2, 2, 2, 2] ]

print("Array A =>")
printMat(matrix_A,4,4)

9
matrix_B = [ [1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[2, 2, 2, 2] ]

print("Array B =>")
printMat(matrix_B,4,4)

result_matrix = multiply_matrix(matrix_A, matrix_B)

print("Result Array =>")


printMat(result_matrix,4,4)

Output:
Array A =>
1111
2222
3333
2222

Array B =>
1111
2222
3333
2222

Result Array =>


8888
16 16 16 16
24 24 24 24
16 16 16 16

10
Performance 25

Record 15

Viva 10

Total 50

Result:
Thus the Divide and Conquer algorithm using Strassen’s Matrix Multiplication was
executed successfully and output was verified

11
12
DATE:
DECREASE AND CONQUER –
[Link] TOPOLOGICAL SORTING

Aim:
To implement Decrease and Conquer approach to topological sorting.

Algorithm:

Step 1: Start with a function called topological_sort(graph) which takes a directed graph as
input.

Step 2: Initialize an empty stack and a list to store the visited nodes.

Step 3: For each node in the graph, if it has not been visited, call the function visit(node)
recursively.

Step 4: In the visit(node) function, mark the current node as visited, then recursively
call the visit function for each of its neighbors (nodes it has an edge pointing to) which
have notbeen visited yet.

Step 5: After all the neighbors of the current node have been visited, push the current node
tothe stack.

Step 6: Once the visit function has been called for all nodes in the graph, the stack
willcontain the nodes in topological order.

Step 7: Return the stack as the output.

Step 8: End the function

Program:

# Python program to print topological sorting of a DAG


from collections import defaultdict

# Class to represent a graph

class Graph:
def init (self, vertices):
[Link] = defaultdict(list) # dictionary containing adjacency List
self.V = vertices # No. of vertices

13
# function to add an edge to graph
def addEdge(self, u, v):
[Link][u].append(v)

# A recursive function used by topologicalSort


def topologicalSortUtil(self, v, visited, stack):

# Mark the current node as visited.


visited[v] = True

# Recur for all the vertices adjacent to this vertex


for i in [Link][v]:
if visited[i] == False:
[Link](i, visited, stack)

# Push current vertex to stack which stores result


[Link](v)

# The function to do Topological Sort. It uses recursive


# topologicalSortUtil()
def topologicalSort(self):
# Mark all the vertices as not visited
visited = [False]*self.V
stack = []

# Call the recursive helper function to store Topological


# Sort starting from all vertices one by one
for i in range(self.V):
if visited[i] == False:
[Link](i, visited, stack)

# Print contents of the stack


print(stack[::-1]) # return list in reverse order

14
# Driver Code
if __name == ' main ':
g = Graph(6)
[Link](5, 2)
[Link](5, 0)
[Link](4, 0)
[Link](4, 1)
[Link](2, 3)
[Link](3, 1)

print("Following is a Topological Sort of the given graph")

# Function Call
[Link]()

Output:-

Following is a Topological Sort of the given graph


[5, 4, 2, 3, 1, 0]

15
Performance 25

Record 15

Viva 10

Total 50

Result:

Thus the Decrease and Conquer approach to topological sorting was executed successfully
andoutput was verified.

16
17
DATE:
TRANSFORM AND CONQUER - HEAP SORT
[Link]

Aim:
To implement Transform and Conquer using Heap Sort.

Algorithm:

Step 1: Create a dictionary to store the indegree of each vertex and initialize it to 0 for all
vertices.

Step 2: Create a graph representation using an adjacency list or adjacency matrix,


whereeach vertex is a keyand the value is a list of its neighbors.

Step 3: Traverse the edges of the graph and for each edge (u, v), increment the indegree of
vertex v in theindegree dictionary.

Step 4: Create a priority queue (heap) and insert all the vertices with indegree 0.

Step 5: While the heap is not empty:

Step 6: Pop the vertex with the highest priority from the heap.

Step 7: Add this vertex to the result list.

Step 8: For each neighbor of the popped vertex, decrement its indegree.

Step 9: If a neighbor's indegree becomes 0, insert it into the heap.

Step 10: If the result list contains all the vertices, return the list as the topological ordering,
otherwise, return None as the graph has a cycle

18
Program:

# Python program for implementation of heap Sort

# To heapify subtree rooted at index i.


# n is size of heap

def heapify(arr, N, i):


largest = i # Initialize largest as root
l = 2 * i + 1 # left = 2*i + 1

r = 2 * i + 2 # right = 2*i + 2

# See if left child of root exists and is


# greater than root
if l < N and arr[largest] < arr[l]:
largest = l

# See if right child of root exists and is


# greater than root
if r < N and arr[largest] < arr[r]:
largest = r

# Change root, if needed


if largest != i:
arr[i], arr[largest] = arr[largest], arr[i] # swap

# Heapify the root.


heapify(arr, N, largest)

# The main function to sort an array of given size

def heapSort(arr):
N = len(arr)

# Build a maxheap.
for i in range(N//2 - 1, -1, -1):
heapify(arr, N, i)

# One by one extract elements


for i in range(N-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # swap
heapify(arr, i, 0)

19
# Driver's code
if __name == ' main ':
arr = [12, 11, 13, 5, 6, 7]

# Function call
heapSort(arr)
N = len(arr)

print("Sorted array is")


for i in range(N):
print("%d" % arr[i], end=" ")

Output :-

Sorted array is
5 6 7 11 12 13

20
Performance 25
Record 15
Viva 10
Total 50

Result:
Thus the Transform and Conquer using Heap Sort was implemented and output was verified
successfully.

21
22
DATE:
[Link] DYNAMIC PROGRAMMING - COIN CHANGING

Aim:
To implement Dynamic Programming using Coin Changing Problem

(A) Coin Changin

ProblemAlgorithm:

Step 1: Define a function coin_change(coins, amount) that takes in a list of coin


denominations and a target
amount as input.

Step 2: Create a list dp of length (amount + 1) and initialize it with the value of infinity.

Step 3: Set dp[0] = 0, as the minimum number of coins needed to make 0 amount is 0.

Step 4: Iterate through the range 1 to amount+1 and for each i, iterate through the coin
denominations.

Step 5: For each coin denomination, check if the coin value is less than or equal to i,
if true then check ifdp[i - coin value] + 1 is less than dp[i], if true then update dp[i] =
dp[i -coin value] + 1.

Step 6: Return dp[amount] as the minimum number of coins needed to make the
targetamount.

23
Program:
# Recursive Python3 program for
# coin change problem.

# Returns the count of ways we can sum


# coins[0...n-1] coins to get sum "sum"

def count(coins, n, sum):

# If sum is 0 then there is 1


# solution (do not include any coin)
if (sum == 0):
return 1
# If sum is less than 0 then no
# solution exists
if (sum < 0):
return 0

# If there are no coins and sum


# is greater than 0, then no
# solution exist
if (n <= 0):
return 0

# count is sum of solutions (i)


# including coins[n-1] (ii) excluding coins[n-1]
return count(coins, n - 1, sum) + count(coins, n, sum-coins[n-1])

# Driver program to test above function


coins = [1, 2, 3]
n = len(coins)
print(count(coins, n, 5))

Output
5

24
Performance 25

Record 15
Viva 10

Total 50

RESULT:

Thus the Dynamic Programming using Coin Changing Problem, Warshall’s .


25
DATE:
DYNAMIC PROGRAMMING - WARSHALL’S
[Link]
ALGORITHM

Aim:
To implement Dynamic Programming using Warshall’s algorithm

AlgorithmWarshall’s

Algorithm:

Step 1: Define a function Warshall(graph) that takes in a graph represented as an adjacency


matrix as input

Step 2: Create a matrix dist of the same size as the input graph, and initialize it with the
graph itself.

Step 3: Iterate through the range of the number of vertices, k.

Step 4: Nest two more loops, one to iterate through the range of the number of rows, i and
another to iteratethrough the range of the number of columns, j.

Step 5: If dist[i][j] > dist[i][k] + dist[k][j], then update dist[i][j] = dist[i][k] + dist[k][j].

Step 6: Return the dist matrix.

26
Program:

# Python3 Program for Floyd Warshall Algorithm

# Number of vertices in the graph


V=4

# Define infinity as the large


# enough value. This value will be
# used for vertices not connected to each other
INF = 99999

# Solves all pair shortest path


# via Floyd Warshall Algorithm

def floydWarshall(graph):

""" dist[][] will be the output


matrix that will finally
have the shortest distances
between every pair of vertices """
""" initializing the solution matrix
same as input graph matrix
OR we can say that the initial
values of shortest distances
are based on shortest paths considering no
intermediate vertices """

dist = list(map(lambda i: list(map(lambda j: j, i)), graph))

""" Add all vertices one by one


to the set of intermediate
vertices.
---> Before start of an iteration,
we have shortest distances
between all pairs of vertices
such that the shortest
distances consider only the

27
vertices in the set
{0, 1, 2, .. k-1} as intermediate vertices.
----> After the end of a
iteration, vertex no. k is
added to the set of intermediate
vertices and the
set becomes {0, 1, 2, .. k}
"""
for k in range(V):

# pick all vertices as source one by one


for i in range(V):

# Pick all vertices as destination for the


# above picked source
for j in range(V):

# If vertex k is on the shortest path from


# i to j, then update the value of dist[i][j]
dist[i][j] = min(dist[i][j],
dist[i][k] + dist[k][j]
)
printSolution(dist)

28
# Driver's code
if __name == " main ":
"""
10
(0)------->(3)
| /|\
5| |
| |1
\|/ |

(1)------->(2)
3 """
graph = [[0, 5, INF, 10],
[INF, 0, 3, INF],
[INF, INF, 0, 1],
[INF, INF, INF, 0]
]
# Function call
floydWarshall(graph)

Output:
Following matrix shows the shortest distancesbetween every pair of vertices
0 5 8 9
INF 0 3 4
INF INF 0 1
INF INF INF 0

29
Performance 25

Record 15

Viva 10

Total 50

RESULT:

Thus the Dynamic Programming using Coin Changing Problem, Warshall’s algorithms

30
DATE:
[Link] DYNAMIC PROGRAMMING - Floyd’s Algorithm

Aim:

To implement Dynamic Programming using Floyd’s Algorithm

Floyd’s Algorithm:

Step 1: Define a function Floyd(graph) that takes in a graph represented as an


adjacencymatrix as input.

Step 2: Create a matrix dist of the same size as the input graph, and initialize it with the
graphitself.

Step 3: Iterate through the range of the number of vertices, k.

Step 4: Nest two more loops, one to iterate through the range of the number of rows, i and
another to iterate through the range of the number of columns, j.

Step 5: If dist[i][j] > dist[i][k] + dist[k][j], then update dist[i][j] = dist[i][k] + dist[k][j].

Step 6: Return the dist matrix.

31
Program
# python code for the above approach
class Solution:

def shortest_paths(self,grid, V):


dist = [float('inf')] *V
# Taking 0 as our source dist[0] = 0
# Relaxing V-1times
for i in range(V):
# For each value in the given
# list of [u, v,wt]
for u, v, wt ingrid:
# If there exists a better

If dist[u]!= float(‘int’) and dist[u]+wt< dist[v]:


dist[v] = dist[u] + wt

for u, v, wt in grid:

if dist[u] != float('inf') and dist[u] + wt< dist[v]:


print("ERROR ALERT, Negative Cycle exists")
print("The shortesrt distances from ")
for i in range(V):
print (" 0 to", i, "--->", dist[i])

# Driver code

If __name__==’ __main__”

V=6
grid = [[0, 1, 2], [0, 3, 5], [0, 4, 3], [1, 0, 3], [1, 5, 6], [1, 2, 2], [1, 3, 2],
[2, 5, 1], [2, 3, 1], [3, 4, 1], [4, 3, 2]]
s1 = Solution()
# Function call

s1.shortest_paths(grid, V)

32
Output:-

The shortest distances from

0 to 0 ---> 0

0 to 1 ---> 2

0 to 2 ---> 4

0 to 3 ---> 4

0 to 4 ---> 3

0 to 5 ---> 5

Performance 25

Record 15

Viva 10

Total 50

RESULT:

Thus the Dynamic Programming using Floyd’salgorithms

33
DATE:
[Link] DYNAMIC PROGRAMMING – Knapsack Problem

Aim:
To implement Dynamic Programming using Knapsack Problem.

Algorithm:

Step 1: Define a function knapsack(items, weight_limit) that takes in a list of items


represented as tuples(value, weight) and a weight limit as input.

Step 2: Create a 2D list dp of length (weight_limit + 1) x (number of items + 1) and


initialize it with 0.

Step 3: Iterate through the range 1 to number of items + 1, i, and for each i, iterate
through the range 0 toweight_limit + 1, w.

Step 4: If the weight of the i-th item is less than or equal to w, then check if dp[i-1][w] is
greater than dp[i- 1][w-weight of i-th item] + value of i-th item. If true then update dp[i][w]
= dp[i-1][w-weight of i-th item] +value of i-th item

Step 5: Otherwise, set dp[i][w] = dp[i-1][w]

Step 6: Return dp[number of items][weight_limit] as the maximum value that can be


obtained with the given weight limit.

34
Program:

# A naive recursive implementation


# of 0-1 Knapsack Problem

# Returns the maximum value that


# can be put in a knapsack of
# capacity W

def knapSack(W, wt, val, n):

# Base Case
if n == 0 or W == 0:
return 0

# If weight of the nth item is


# more than Knapsack of capacity W,
# then this item cannot be included
# in the optimal solution
if (wt[n-1] > W):
return knapSack(W, wt, val, n-1)

# return the maximum of two cases:


# (1) nth item included
# (2) not include

35
else:

return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),


knapSack(W, wt, val, n-1))

# end of function knapSack

# Driver Code
if __name == ' main ':
profit = [60, 100, 120]
weight = [10, 20, 30]
W = 50
n = len(profit)
print knapSack(W, weight, profit, n)

Performance 25

Record 15

Viva 10

Total 50

RESULT:

Thus the Dynamic Programming using Knapsack Problem Done successfully

36
37
DATE: GREEDY TECHNIQUE - DIJKSTRA’S
ALGORITHM,
[Link]

Aim:

To implement Greedy Technique using Dijkstra’s Algorithm .

(A)Dijkstra’s Algorithm:

Step 1: Define a function Dijkstra(graph, start) that takes in a weighted graph represented
as an adjacency list and a starting vertex as input.

Step 2: Create an empty priority queue (min heap) and a dictionary to store the shortest
distance from the start vertex to each vertex.

Step 3: Initialize the dictionary with a distance of infinity for all vertices except the
start vertex, which should have a distance of 0.

Step 4: Insert the start vertex into the priority queue with a distance of 0.

Step 5: While the priority queue is not empty:

Step 6: Pop the vertex with the smallest distance from the priority queue.

Step 7: For each neighbor of the popped vertex:

Step 8: If the distance to the neighbor can be shortened by going through the popped
vertex, update the distance in the dictionary and insert the neighbor into the priority
queue.

Step 9: Return the dictionary containing the shortest distance from the start vertex to
each vertex as the result.

Program:

# Python program for Dijkstra's single


# source shortest path algorithm. The program is
# for adjacency matrix representation of the graph

38
# Library for INT_MAX
import sys

class Graph():

def init (self, vertices):


self.V = vertices
[Link] = [[0 for column in range(vertices)]
for row in range(vertices)]

def printSolution(self, dist):


print("Vertex \tDistance from Source")
for node in range(self.V):
print(node, "\t", dist[node])

# A utility function to find the vertex with


# minimum distance value, from the set of vertices
# not yet included in shortest path tree
def minDistance(self, dist, sptSet):

# Initialize minimum distance for next node


min = [Link]

# Search not nearest vertex not in the


# shortest path tree
for u in range(self.V):
if dist[u] < min and sptSet[u] == False:
min = dist[u]
min_index = u

return min_index

# Function that implements Dijkstra's single source


# shortest path algorithm for a graph represented
# using adjacency matrix representation
def dijkstra(self, src):

dist = [[Link]] * self.V


dist[src] = 0
sptSet = [False] * self.V

for cout in range(self.V):

# Pick the minimum distance vertex from


39
# the set of vertices not yet processed.
# x is always equal to src in first iteration
x = [Link](dist, sptSet)

# Put the minimum distance vertex in the


# shortest path tree
sptSet[x] = True

# Update dist value of the adjacent vertices


# of the picked vertex only if the current
# distance is greater than new distance and
# the vertex in not in the shortest path tree
for y in range(self.V):
if [Link][x][y] > 0 and sptSet[y] == False and \
dist[y] > dist[x] + [Link][x][y]:
dist[y] = dist[x] + [Link][x][y]

[Link](dist)

# Driver's code
if __name == " main ":
g = Graph(9)
[Link] = [[0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0]
]

[Link](0)

40
Output:

Vertex Distance from source


0 0
1 4
2 12
3 19
4 21
5 11
6 9
7 8
8 14

Performance 25

Record 15

Viva 10

Total 50

RESULT:

Thus the Greedy Technique using Dijkstra’s Algorithm .


Done successfully

41
42
43
DATE: GREEDY TECHNIQUE –HUFFMANN
TREE AND CODES
[Link]

Aim:

To implement Greedy Technique using Huffmann Tree and Codes

Huffmann and codes algorithm:

Step 1: Create a list of tuples for each character in the text, where each tuple
containsthe character, its frequency, and a unique identifier.

Step 2: Sort the list of tuples in ascending order of frequency.

Step 3: Create a leaf node for each tuple and add it to a priority queue (min heap) based on
the frequency.

Step 4: While the priority queue has more than one node: Step 5: Remove the two nodes
with the smallest frequency from the priority queue. Step 6: Create a new internal node
witha frequency equal to the sum of the frequencies of the removed nodes. Step 7: Make
the removed nodes left and right children of the new internal node. Step 8: Insert the
new internal node into the priority queue.

Step 9: The remaining node in the priority queue is the root of the Huffman tree.

Step 10: Traverse the Huffman tree and assign 0 to the left child and 1 to the right
childat each internal node.

Step 11: For each leaf node, the code is the path from the root to the leaf, where left child is
represented by0 and right child is represented by 1.

Step 12: Store the codes for each character in a dictionary for easy lookup and decoding.

44
Program:

# A Huffman Tree Node


import heapq

class node:
def init (self, freq, symbol, left=None, right=None):
# frequency of symbol
[Link] = freq

# symbol name (character)


[Link] = symbol

# node left of current node


[Link] = left

# node right of current node


[Link] = right

# tree direction (0/1)


[Link] = ''

def lt (self, nxt):


return [Link] < [Link]

# utility function to print huffman


# codes for all symbols in the newly
# created Huffman tree

45
def printNodes(node, val=''):

# huffman code for current node


newVal = val + str([Link])

# if node is not an edge node


# then traverse inside it
if([Link]):
printNodes([Link], newVal)
if([Link]):
printNodes([Link], newVal)

# if node is edge node then


# display its huffman code
if(not [Link] and not [Link]):
print(f"{[Link]} -> {newVal}")

# characters for huffman tree


chars = ['a', 'b', 'c', 'd', 'e', 'f']

# frequency of characters
freq = [5, 9, 12, 13, 16, 45]

# list containing unused nodes


nodes = []

# converting characters and frequencies


# into huffman tree nodes
for x in range(len(chars)):
[Link](nodes, node(freq[x], chars[x]))

while len(nodes) > 1:

46
# sort all the nodes in ascending order
# based on their frequency
left = [Link](nodes)
right = [Link](nodes)

# assign directional value to these nodes


[Link] = 0
[Link] = 1

# combine the 2 smallest nodes to create


# new node as their parent
newNode = node([Link]+[Link], [Link]+[Link], left, right)

[Link](nodes, newNode)

# Huffman Tree is ready!


printNodes(nodes[0])

Output:
f -> 0
c -> 100
d -> 101
a -> 1100
b -> 1101
e -> 111

47
Performance 25

Record 15

Viva 10

Total 50

Result:
Thus the Greedy Technique using Huffmann Tree and Codes has been implemented and
output was verified successfully.

48
49
DATE: ITERATIVE IMPROVEMENT - SIMPLEX
METHOD
[Link]

Aim:

To implement Iterative Improvement using Simplex Method.

Algorithm:

Step 1: Write the problem in standard form, where the objective function is to be
maximized or minimized,and the constraints are in the form of inequalities or
equalities.

Step 2: Create the initial simplex tableau by writing the constraints as equations in
matrix form, andincluding the objective function as the last row.

Step 3: Check if the solution is feasible by checking if all the values in the right-hand side
column are non-negative. If not, the problem is infeasible.

Step 4: Choose the pivot column, which is the column with the most negative
coefficient in the last row(objective function row).

Step 5: Choose the pivot row, which is the row with the smallest positive ratio of the
right-hand side columnand the pivot column.

Step 6: Pivot on the chosen pivot element and perform row operations to obtain a new
tableau.

Step 7: Check if the objective function value has improved. If not, go to step 4. If it has,
check if there are any negative values in the last row (objective function row) other than
theright-hand side column. If not, thesolution is optimal. If there are, go to step 4.

Step 8: The optimal solution can be read off the right-hand side column of the final
tableau, where thevariables are the basic variables and the values are the
correspondingoptimal values.

50
Program:

import numpy as np
from fractions import Fraction # so that numbers are not displayed in decimal.

print("\n ****SiMplex Algorithm ****\n\n")

# inputs

# A will contain the coefficients of the constraints


A = [Link]([[1, 1, 0, 1], [2, 1, 1, 0]])
# b will contain the amount of resources
b = [Link]([8, 10])
# c will contain coefficients of objective function Z
c = [Link]([1, 1, 0, 0])

# B will contain the basic variables that make identity matrix


cb = [Link](c[3])
B = [Link]([[3], [2]])
# cb contains their corresponding coefficients in Z
cb = [Link]((cb, c[2]))
xb = [Link]([b])
# combine matrices B and cb
table = [Link]((B, cb))
table = [Link]((table, xb))
# combine matrices B, cb and xb
# finally combine matrix A to form the complete simplex table
table = [Link]((table, A))
# change the type of table to float
table = [Link](table, dtype ='float')
# inputs end

# if min problem, make this var 1


MIN = 0

print("Table at itr = 0")


print("B \tCB \tXB \ty1 \ty2 \ty3 \ty4")
for row in table:
for el in row:
# limit the denominator under 100
print(Fraction(str(el)).limit_denominator(100), end ='\t')
print()
print()
print("Simplex Working ... ")

51
# when optimality reached it will be made 1
reached = 0
itr = 1
unbounded = 0
alternate = 0

while reached == 0:

print("Iteration: ", end =' ')


print(itr)
print("B \tCB \tXB \ty1 \ty2 \ty3 \ty4")
for row in table:
for el in row:
print(Fraction(str(el)).limit_denominator(100), end ='\t')
print()

# calculate Relative profits-> cj - zj for non-basics


i=0
rel_prof = []
while i<len(A[0]):
rel_prof.append(c[i] - [Link](table[:, 1]*table[:, 3 + i]))
i=i+1

print("rel profit: ", end =" ")


for profit in rel_prof:
print(Fraction(str(profit)).limit_denominator(100), end =", ")
print()
i=0

b_var = table[:, 0]
# checking for alternate solution
while i<len(A[0]):
j=0
present = 0
while j<len(b_var):
if int(b_var[j]) == i:
present = 1
break;
j+= 1
if present == 0:
if rel_prof[i] == 0:
alternate = 1
print("Case of Alternate found")
# print(i, end =" ")
i+= 1
print()
flag = 0
52
for profit in rel_prof:
if profit>0:
flag = 1
break
# if all relative profits <= 0
if flag == 0:
print("All profits are <= 0, optimality reached")
reached = 1
break

# kth var will enter the basis


k = rel_prof.index(max(rel_prof))
min = 99999
i = 0;
r = -1
# min ratio test (only positive values)
while i<len(table):
if (table[:, 2][i]>0 and table[:, 3 + k][i]>0):
val = table[:, 2][i]/table[:, 3 + k][i]
if val<min:
min = val
r = i # leaving variable
i+= 1

# if no min ratio test was performed


if r ==-1:
unbounded = 1
print("Case of Unbounded")
break

print("pivot element index:", end =' ')


print([Link]([r, 3 + k]))

pivot = table[r][3 + k]
print("pivot element: ", end =" ")
print(Fraction(pivot).limit_denominator(100))

# perform row operations


# divide the pivot row with the pivot element
table[r, 2:len(table[0])] = table[
r, 2:len(table[0])] / pivot

# do row operation on other rows


i=0
while i<len(table):
if i != r:
table[i, 2:len(table[0])] = table[i,
53
2:len(table[0])] - table[i][3 + k] *
table[r, 2:len(table[0])]
i += 1

# assign the new basic variable


table[r][0] = k
table[r][1] = c[k]

print()
print()
itr+= 1

print()

print("***************************************************************")
if unbounded == 1:
print("UNBOUNDED LPP")
exit()
if alternate == 1:
print("ALTERNATE Solution")

print("optimal table:")
print("B \tCB \tXB \ty1 \ty2 \ty3 \ty4")
for row in table:
for el in row:
print(Fraction(str(el)).limit_denominator(100), end ='\t')
print()
print()
print("value of Z at optimality: ", end =" ")

basis = []
i=0
sum = 0
while i<len(table):
sum += c[int(table[i][0])]*table[i][2]
temp = "x"+str(int(table[i][0])+1)
[Link](temp)
i+= 1
# if MIN problem make z negative
if MIN == 1:
print(-Fraction(str(sum)).limit_denominator(100))
else:
print(Fraction(str(sum)).limit_denominator(100))
print("Final Basis: ", end =" ")
print(basis)
54
print("Simplex Finished...")
print()

Performance 25

Record 15

Viva 10

Total 50

Result:

Thus the Iterative Improvement using Simplex Method has been implemented and output
verified successfully

55
56
DATE:
BACKTRACKING - N-QUEEN PROBLEM,
[Link]

Aim:
To implement Backtracking using N-Queen Problem .

N-Queen Problem Algorithm:

Step 1: Define a function solveNQueens(n) that takes in the number of queens as input.

Step 2: Initialize a 2D list of size nxn to represent the chessboard and set all elements to 0.

Step 3: Define a recursive function backtrack(board, col) that takes in the current chessboard
and the currentcolumn as input.

Step 4: If the current column is equal to the number of queens, then a valid solution
hasbeen found, add itto the result list.

Step 5: Iterate through the rows of the current column, and for each row, check if it is
safe to place a queenin that position by checking if it is not in the same row, column, or
diagonalas any other previously placedqueens.

Step 6: If the position is safe, place a queen in that position, mark the position in the
chessboard as 1, andcall the backtrack function with the updated chessboard and the
nextcolumn.

Step 7: After the recursive call, remove the queen from the current position
and mark it as 0 in thechessboard.

Step 8: Call the backtrack function with the initial chessboard and the first column

Step 9: Return the list of valid solutions

Program:

# Python3 program to solve N Queen


# Problem using backtracking

global N
N=4

57
def printSolution(board):
for i in range(N):
for j in range(N):
if board[i][j] == 1:
print("Q",end=" ")
else:
print(".",end=" ")
print()

# A utility function to check if a queen can


# be placed on board[row][col]. Note that this
# function is called when "col" queens are
# already placed in columns from 0 to col -1.
# So we need to check only left side for
# attacking queens
def isSafe(board, row, col):

# Check this row on left side


for i in range(col):
if board[row][i] == 1:
return False

# Check upper diagonal on left side


for i, j in zip(range(row, -1, -1),
range(col, -1, -1)):
if board[i][j] == 1:
return False

# Check lower diagonal on left side


for i, j in zip(range(row, N, 1),
range(col, -1, -1)):
if board[i][j] == 1:
return False

return True

def solveNQUtil(board, col):

# Base case: If all queens are placed


# then return true
if col >= N:
return True

# Consider this column and try placing


# this queen in all rows one by one
for i in range(N):
58
if isSafe(board, i, col):

# Place this queen in board[i][col]


board[i][col] = 1

# Recur to place rest of the queens


if solveNQUtil(board, col + 1) == True:
return True

# If placing queen in board[i][col


# doesn't lead to a solution, then
# queen from board[i][col]
board[i][col] = 0

# If the queen can not be placed in any row in


# this column col then return false
return False

# This function solves the N Queen problem using


# Backtracking. It mainly uses solveNQUtil() to
# solve the problem. It returns false if queens
# cannot be placed, otherwise return true and
# placement of queens in the form of 1s.
# note that there may be more than one
# solutions, this function prints one of the
# feasible solutions.
def solveNQ():
board = [[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]

if solveNQUtil(board, 0) == False:
print("Solution does not exist")
return False

printSolution(board)
return True

# Driver Code
if __name == ' main ':
solveNQ()

59
output:-
..Q.
Q...
...Q
.Q..

Performance 25

Record 15

Viva 10

Total 50

Result:

Thus the Backtracking using N-Queen Problem has beenimplemented and output was
verified successfully.

60
DATE:
BACKTRACKING -SUBSET SUMPROBLEM
[Link]
Aim:

To implement Backtracking using SUBSET SUMPROBLEM

Subset Sum Problem Algorithm:

Step 1: Define a function subset_sum(numbers, target) that takes in a set of integers


anda target sum asinput.

Step 2: Initialize an empty list to store the subsets that add up to the target sum.

Step 3: Define a recursive function backtrack(start, subset, current_sum) that takes in


thecurrent startingindex, a subset of integers and the current sum as input.

Step 4: If the current sum is equal to the target sum, add the subset to the result list.

Step 5: If the current sum is greater than the target sum, return without taking any
furtheraction.

Step 6: Iterate through the remaining elements in the numbers array, starting from the
current index.

Step 7: For each element, add it to the current subset, and call the backtrack function
with the updatedsubset and current sum.

Step 8: After the recursive call, remove the last element from the current subset.

Step 9: Call the backtrack function with the initial parameters, the first index of the numbers
array, an emptysubset, and a current sum of 0.
Step 10: Return the list of subsets that add up to the target sum.

61
Program:

# Python program for the above approach

# Taking the matrix as globally

tab = [[-1 for i in range(2000)] for j in range(2000)]

# Check if possible subset with

# given sum is possible or not

def subsetSum(a, n, sum):

# If the sum is zero it means

# we got our expected sum

if (sum == 0):

return 1

if (n <= 0):

return 0

# If the value is not -1 it means it

# already call the function

# with the same value.

# it will save our from the repetition.


62
if (tab[n - 1][sum] != -1):

return tab[n - 1][sum]

# If the value of a[n-1] is

# greater than the sum.

# we call for the next value

if (a[n - 1] > sum):

tab[n - 1][sum] = subsetSum(a, n - 1, sum)

return tab[n - 1][sum]

else:

# Here we do two calls because we

# don't know which value is

# full-fill our criteria

# that's why we doing two calls

tab[n - 1][sum] = subsetSum(a, n - 1, sum)

return tab[n - 1][sum] or subsetSum(a, n - 1, sum - a[n - 1])

63
Driver Code
if __name == ' main ':

n=5

a = [1, 5, 3, 7, 4]

sum = 12

if (subsetSum(a, n, sum)):
print("YES")
else:
print("NO")

Output:
yes

Performance 25

Record 15

Viva 10

Total 50

Result:

Thus the Backtracking using Subset Sum Problem has beenimplemented and output
was verified successfully.

64
65
DATE:
Branch and Bound - Assignment Problem
[Link]

Aim:

To implement Branch and Bound in Assignment Problem .

Assignment Problem Algorithm:

Step 1: Formulate the problem as an assignment problem, where there is a set of


workersand a set of tasks,and the goal is to find the optimal assignment of workers to
tasks such that the total cost is minimized.

Step 2: Create an initial feasible solution by using a method such as the


Hungarian algorithm or the North-West corner method to find an initial
assignment of workers totasks.

Step 3: Create a lower bound for the problem by finding the minimum value of each
row and column in thecost matrix and subtracting the minimum value from each
element in thecorresponding row or column.
Repeat this process until all the rows and columns have been processed.

Step 4: Use the lower bound as a threshold for the branch and bound algorithm. At
each branch, check if thelower bound is less than or equal to the current best
solution. If it is, continue branching. If not, prune the branch.

Step 5: At each leaf node of the branch and bound tree, check if a complete feasible
solutionhas been [Link] it has, check if it is better than the current best solution. If it is,
update the best solution.

Step 6: Repeat steps 4 and 5 until the entire branch and bound tree has been searched.

Step 7: The final solution will be the best solution found during the branch and bound
search.

Program:

// Program to solve Job Assignment problem


// using Branch and Bound
#include <bits/stdc++.h>
using namespace std;
#define N 4
66
// state space tree node
struct Node
{
// stores parent node of current node
// helps in tracing path when answer is found
Node* parent;

// contains cost for ancestors nodes


// including current node
int pathCost;

// contains least promising cost


int cost;

// contain worker number


int workerID;

// contains Job ID
int jobID;

// Boolean array assigned will contains


// info about available jobs
bool assigned[N];
};

// Function to allocate a new search tree node


// Here Person x is assigned to job y
Node* newNode(int x, int y, bool assigned[],
Node* parent)
{
Node* node = new Node;

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


node->assigned[j] = assigned[j];
node->assigned[y] = true;

node->parent = parent;
node->workerID = x;
node->jobID = y;

return node;
}

// Function to calculate the least promising cost


// of node after worker x is assigned to job y.
int calculateCost(int costMatrix[N][N], int x,
int y, bool assigned[])
67
{
int cost = 0;

// to store unavailable jobs


bool available[N] = {true};

// start from next worker


for (int i = x + 1; i < N; i++)
{
int min = INT_MAX, minIndex = -1;

// do for each job


for (int j = 0; j < N; j++)
{
// if job is unassigned
if (!assigned[j] && available[j] &&
costMatrix[i][j] < min)
{
// store job number
minIndex = j;

// store cost
min = costMatrix[i][j];
}
}

// add cost of next worker


cost += min;

// job becomes unavailable


available[minIndex] = false;
}

return cost;
}

// Comparison object to be used to order the heap


struct comp
{
bool operator()(const Node* lhs,
const Node* rhs) const
{
return lhs->cost > rhs->cost;
}
};

// print Assignments
68
void printAssignments(Node *min)
{
if(min->parent==NULL)
return;

printAssignments(min->parent);
cout << "Assign Worker " << char(min->workerID + 'A')
<< " to Job " << min->jobID << endl;

// Finds minimum cost using Branch and Bound.


int findMinCost(int costMatrix[N][N])
{
// Create a priority queue to store live nodes of
// search tree;
priority_queue<Node*, std::vector<Node*>, comp> pq;

// initialize heap to dummy node with cost 0


bool assigned[N] = {false};
Node* root = newNode(-1, -1, assigned, NULL);
root->pathCost = root->cost = 0;
root->workerID = -1;

// Add dummy node to list of live nodes;


[Link](root);

// Finds a live node with least cost,


// add its childrens to list of live nodes and
// finally deletes it from the list.
while (![Link]())
{
// Find a live node with least estimated cost
Node* min = [Link]();

// The found node is deleted from the list of


// live nodes
[Link]();

// i stores next worker


int i = min->workerID + 1;

// if all workers are assigned a job


if (i == N)
{
printAssignments(min);
return min->cost;
69
}

// do for each job


for (int j = 0; j < N; j++)
{
// If unassigned
if (!min->assigned[j])
{
// create a new tree node
Node* child = newNode(i, j, min->assigned, min);

// cost for ancestors nodes including current node


child->pathCost = min->pathCost + costMatrix[i][j];

// calculate its lower bound


child->cost = child->pathCost +
calculateCost(costMatrix, i, j, child->assigned);

// Add child to list of live nodes;


[Link](child);
}
}
}
}

// Driver code
int main()
{
// x-coordinate represents a Worker
// y-coordinate represents a Job
int costMatrix[N][N] =
{
{9, 2, 7, 8},
{6, 4, 3, 7},
{5, 8, 1, 8},
{7, 6, 9, 4}
};

/* int costMatrix[N][N] =
{
{82, 83, 69, 92},
{77, 37, 49, 92},
{11, 69, 5, 86},
{ 8, 9, 98, 23}
};
*/
70
/* int costMatrix[N][N] =
{
{2500, 4000, 3500},
{4000, 6000, 3500},
{2000, 4000, 2500}
};*/

/*int costMatrix[N][N] =
{
{90, 75, 75, 80},
{30, 85, 55, 65},
{125, 95, 90, 105},
{45, 110, 95, 115}
};*/

cout << "\nOptimal Cost is "


<< findMinCost(costMatrix);

return 0;
}

71
Output :
Assign Worker A to Job 1
Assign Worker B to Job 0
Assign Worker C to Job 2
Assign Worker D to Job 3

Performance 25

Record 15

Viva 10

Total 50

Result:
Thus the Branch and Bound in Assignment Problem has been implemented and output
was verified successfully.

72
DATE:
Branch and Bound Traveling Salesman Problem
[Link]`

Aim:

To implement Branch and Bound in Traveling Salesman Problem.

Travelling Salesman Problem Algorithm:

Step 1: Formulate the problem as a TSP, where there is a set of cities and the goal is
tofind the shortestpossible route that visits each city exactly once and returns to the
starting city.

Step 2: Create an initial feasible solution by using a method such as Nearest


Neighboror Christofidesalgorithm to find an initial route.

Step 3: Create a lower bound for the problem by using a method such as a Minimum
Spanning Tree (MST)algorithm to find the shortest possible route that visits each
city at least once.

Step 4: Use the lower bound as a threshold for the branch and bound algorithm. At
eachbranch, check if thelower bound is less than or equal to the current best solution.
If it is, continue branching. If not, prune the branch.

Step 5: At each leaf node of the branch and bound tree, check if a complete feasible
solutionhas been [Link] it has, check if it is better than the current best solution. If it is,
update the best solution.

Step 6: Repeat steps 4 and 5 until the entire branch and bound tree has been searched.

Step 7: The final solution will be the best solution found during the branch and bound
search, which will bethe shortest possible route that visits each city exactly once and
returnsto the starting city.

Program:

# Python3 program to implement traveling salesman


# problem using naive approach.
73
from sys import maxsize
from itertools import permutations
V=4

# implementation of traveling Salesman Problem


def travellingSalesmanProblem(graph, s):

# store all vertex apart from source vertex


vertex = []
for i in range(V):
if i != s:
[Link](i)

# store minimum weight Hamiltonian Cycle


min_path = maxsize

next_permutation=permutations(vertex)
for i in next_permutation:

# store current Path weight(cost)


current_pathweight = 0

# compute current path weight


k=s
for j in i:
current_pathweight += graph[k][j]
k=j
current_pathweight += graph[k][s]

# update minimum
min_path = min(min_path, current_pathweight)

return min_path

# Driver Code
if __name == " main ":

# matrix representation of graph


graph = [[0, 10, 15, 20], [10, 0, 35, 25],
[15, 35, 0, 30], [20, 25, 30, 0]]
s=0
print(travellingSalesmanProblem(graph, s))

74
Performance 25

Record 15

Viva 10

Total 50

Result:
Thus the Branch and Bound in Traveling Salesman Problem has been implemented and
output was verified successfully.

75

You might also like