Daa - Integrated Lab Manual
Daa - Integrated Lab Manual
Implement recursive and non-recursive algorithms and study the order of growth from
log2n to n!
AIM:
To Implement recursive and non-recursive algorithms and study the order of growth
from log2n to n!
ALGORITHM:
STEP 5:Stop
PROGRAM
NON RECURSION
def fibonacci(n):
a=0
b=1
if n < 0:
print("Incorrect input")
elif n == 0:
return a
elif n == 1:
return b
else:
for i in range(2, n+1):
c=a+b
a=b
b=c
return b
# Driver Program
print(fibonacci(9))
OUTPUT:
34
RECURSION:
if __name__ == "__main__":
n=5
print(n, "th Fibonacci Number: ")
print(fibonacci(n))
OUTPUT
34
RESULT:
Thus the program to implement recursive and non-recursive algorithms and study
the order of growth from log2n to n! is executed and verified successfully.
2. Divide and Conquer - Strassen’s Matrix Multiplication
AIM :
ALGORITHM:
STEP 2: Divide the matrices A and B into smaller submatrices of the size n/2xn/2.
STEP 3:Using the formula of scalar additions and subtractions compute smaller
matrices of size n/2.
STEP 4:Recursively compute the seven matrix products Pi=AiBi for i=1,2,…7.
STEP 5:Now compute the by just adding the scalars obtained from above points.
PROGRAM:
ROW_1 = 4
COL_1 = 4
ROW_2 = 4
COL_2 = 4
for i in range(r):
for j in range(c):
print()
print()
print()
print()
for i in range(split_index):
for j in range(split_index):
for i in range(r):
for j in range(c):
a[i][j] = 0
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):
return 0
result_matrix_row = [0] * col_2
if (col_1 == 1):
else:
split_index = col_1 // 2
for i in range(split_index):
for j in range(split_index):
a00[i][j] = matrix_A[i][j]
b00[i][j] = matrix_B[i][j]
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]
return result_matrix
# Driver Code
[2, 2, 2, 2],
[3, 3, 3, 3],
[2, 2, 2, 2] ]
print("Array A =>")
printMat(matrix_A,4,4)
[2, 2, 2, 2],
[3, 3, 3, 3],
[2, 2, 2, 2] ]
print("Array B =>")
printMat(matrix_B,4,4)
printMat(result_matrix,4,4)
OUTPUT :
Array A =>
1 1 1 1
2 2 2 2
3 3 3 3
2 2 2 2
Array B =>
1 1 1 1
2 2 2 2
3 3 3 3
2 2 2 2
RESULT:
Thus the program, Strassen’s Matrix Multiplication by Divide and Conquer technique
is executed and verified successfully.
3. Decrease and Conquer - Topological Sorting
AIM :
To implement a topological sorting program by decrease and conquer method.
ALGORITHM:
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):
self.graph = defaultdict(list) # dictionary containing adjacency List
self.V = vertices # No. of vertices
# function to add an edge to graph
def addEdge(self, u, v):
self.graph[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 self.graph[v]:
if visited[i] == False:
self.topologicalSortUtil(i, visited, stack)
# Push current vertex to stack which stores result
stack.append(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:
self.topologicalSortUtil(i, visited, stack)
# Print contents of the stack
print(stack[::-1]) # return list in reverse order
# Driver Code
if __name__ == '__main__':
g = Graph(6)
g.addEdge(5, 2)
g.addEdge(5, 0)
g.addEdge(4, 0)
g.addEdge(4, 1)
g.addEdge(2, 3)
g.addEdge(3, 1)
print("Following is a Topological Sort of the given graph")
# Function Call
g.topologicalSort()
OUTPUT:
RESULT:
Thus the topological sorting program by decrease and conquer method is executed and
verified successfully.
5. Dynamic programming - Coin change Problem, Warshall’s and Floyd‘s algorithms,
Knapsack Problem
AIM:
To implement a Coin change problem using Dynamic Programming technique.
ALGORITHM:
Include the current coin: Subtract the current coin’s denomination from the target
sum and call the count function recursively with the updated sum and the same set
of coins i.e., count(coins, n, sum – coins[n-1] )
Exclude the current coin: Call the count function recursively with the same sum
and the remaining coins. i.e., count(coins, n-1,sum ).
PROBLEM:
# If number of coins is 0 or sum is less than 0 then there is no way to make the sum.
if (n == 0 or sum < 0):
return 0
return dp[n][sum]
# Driver code
if __name__ == '__main__':
tc = 1
while (tc != 0):
n=3
sum = 5
coins = [1, 2, 3]
dp = [[-1 for i in range(sum+1)] for j in range(n+1)]
res = count(coins, sum, n, dp)
print(res)
tc -= 1
OUTPUT:
5
RESULT:
Thus the Coin change problem using Dynamic Programming technique is executed and
verified successfully.
Warshall’s and Floyd‘s algorithms
AIM:
ALGORITHM:
STEP 3: Define infinity as the large enough value. This value will be used for vertices not
connected to each other.
STEP 4: Add all vertices one by one to the set of intermediate vertices.
PROGRAM:
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
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):
OUTPUT:
The following matrix shows the shortest distances between every pair of vertices
0 5 8 9
INF 0 3 4
INF INF 0 1
INF INF INF 0
RESULT:
Thus the program for Warshall’s and Floyd‘s algorithms using Dynamic Programming
is executed and verified successfully.
AIM:
ALGORITHM:
Step 3: Initialize the first row and the first column of the table to 0 (base case).
Step 4: Iterate through each item and each possible knapsack capacity.
Include the current item if its weight is less than or equal to the current capacity.
Exclude the current item.
Step 6: Update the table entry with the maximum value between the two options.
Step 7: Continue iterating until all items and capacities are considered.
Step 8: The maximum value that can be placed in the knapsack is stored in the last cell of the
table.
PROGRAM:
if i == 0 or w == 0:
K[i][w] = 0
else:
K[i][w] = K[i-1][w]
return K[n][W]
W = 50
n = len(val)
OUTPUT:
220
RESULT:
Thus the Knapsack Problem program using Dynamic Programming method is executed
and verified successfully.
6. Greedy Technique – Dijkstra’s algorithm, Huffman Trees and codes
AIM:
ALGORITHM:
STEP 2: Create a table to store the minimum distances from the source vertex to all other
vertices.
STEP 3: Initialize the distance to the source vertex as 0, and the distances to all other vertices
as infinity.
Find the unprocessed vertex with the minimum distance from the source.
Mark this vertex as processed.
Update the distances to its neighbors if a shorter path is found through this vertex.
Step 6: End the process.
PROGRAM:
class Graph():
self.V = vertices
min = 1e7
for v in range(self.V):
min = dist[v]
min_index = v
return min_index
dist[src] = 0
u = self.minDistance(dist, sptSet)
sptSet[u] = True
for v in range(self.V):
self.printSolution(dist)
# Driver program
g = Graph(9)
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
g.dijkstra(0)
OUTPUT:
RESULT:
Thus the above program using Dijkstra’s algorithm by Greedy Technique is executed and
verified successfully.
Huffman Trees and codes
AIM:
ALGORITHM:
STEP 4: Convert each character and its frequency into a node and add it to the list.
STEP 5: While there are more than one node in the list:
import heapq
class node:
# frequency of symbol
self.freq = freq
self.symbol = symbol
self.left = left
self.right = right
self.huff = ''
if(node.left):
printNodes(node.left, newVal)
if(node.right):
printNodes(node.right, newVal)
# frequency of characters
nodes = []
for x in range(len(chars)):
heapq.heappush(nodes, node(freq[x], chars[x]))
left = heapq.heappop(nodes)
right = heapq.heappop(nodes)
left.huff = 0
right.huff = 1
heapq.heappush(nodes, newNode)
printNodes(nodes[0])
OUTPUT:
f: 0
c: 100
d: 101
a: 1100
b: 1101
e: 111
RESULT:
Thus the above program using Huffman Trees and codes by Greedy Technique is
executed and verified successfully.
7. Iterative improvement - Simplex Method
AIM:
ALGORITHM:
import numpy as np
from fractions import Fraction # so that numbers are not displayed in decimal.
# inputs
b = np.array([8, 10])
c = np.array([1, 1, 0, 0])
cb = np.array(c[3])
B = np.array([[3], [2]])
cb = np.vstack((cb, c[2]))
xb = np.transpose([b])
MIN = 0
for el in row:
print()
print()
print("Simplex Working....")
reached = 0
itr = 1
unbounded = 0
alternate = 0
while reached == 0:
print(itr)
print()
i=0
rel_prof = []
while i<len(A[0]):
i=i+1
print()
i=0
b_var = table[:, 0]
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
i+= 1
print()
flag = 0
if profit>0:
flag = 1
break
if flag == 0:
reached = 1
break
k = rel_prof.index(max(rel_prof))
min = 99999
i = 0;
r = -1
while i<len(table):
min = val
i+= 1
if r ==-1:
unbounded = 1
print("Case of Unbounded")
break
print(np.array([r, 3 + k]))
pivot = table[r][3 + k]
print(Fraction(pivot).limit_denominator(100))
r, 2:len(table[0])] / pivot
i=0
while i<len(table):
if i != r:
table[i, 2:len(table[0])] = table[i,
2:len(table[0])] - table[i][3 + k] *
table[r, 2:len(table[0])]
i += 1
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:")
for el in row:
print(Fraction(str(el)).limit_denominator(100), end ='\t')
print()
print()
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)
basis.append(temp)
i+= 1
if MIN == 1:
print(-Fraction(str(sum)).limit_denominator(100))
else:
print(Fraction(str(sum)).limit_denominator(100))
print(basis)
print("Simplex Finished...")
print()
OUTPUT:
RESULT:
Thus the above a program Iterative improvement by Simplex Method is executed and
verified successfully.
8. Backtracking – N-Queen problem,
AIM:
ALGORITHM:
STEP 5: Repeat the process to find all possible solutions by backtracking and exploring
different queen placements.
STEP 6: If you have explored all possibilities and haven't found any more solutions, stop the
process.
return True
for i in range(N):
if isSafe(board, i, col):
board[i][col] = 1
if solveNQueens(board, col + 1):
return True
board[i][col] = 0
return False
RESULT:
Thus the above N-Queen problem, by Backtracking technique is executed and verified
successfully.
9. Branch and Bound - Assignment problem, Traveling Salesman Problem
AIM:
ALGORITHM:
STEP 2: Define the distances between cities using an adjacency matrix adj and specify the
number of cities N.
STEP 6: Define a function to compute the minimum edge cost from a given city.
STEP 10: Print the minimum cost and the path taken.
import math
maxsize = float('inf')
def copyToFinal(curr_path):
final_path[:N + 1] = curr_path[:]
final_path[N] = curr_path[0]
min = maxsize
for k in range(N):
min = adj[i][k]
return min
for j in range(N):
if i == j:
continue
second = first
first = adj[i][j]
adj[i][j] != first):
second = adj[i][j]
return second
global final_res
if level == N:
if adj[curr_path[level - 1]][curr_path[0]] != 0:
[curr_path[0]]
copyToFinal(curr_path)
final_res = curr_res
return
for i in range(N):
if (adj[curr_path[level-1]][i] != 0 and
visited[i] == False):
temp = curr_bound
if level == 1:
firstMin(adj, i)) / 2)
else:
firstMin(adj, i)) / 2)
curr_path[level] = i
visited[i] = True
curr_bound = temp
# Also reset the visited array
for j in range(level):
if curr_path[j] != -1:
visited[curr_path[j]] = True
def TSP(adj):
curr_bound = 0
curr_path = [-1] * (N + 1)
visited = [False] * N
for i in range(N):
curr_bound += (firstMin(adj, i) +
secondMin(adj, i))
curr_bound = math.ceil(curr_bound / 2)
# in curr_path[] is 0
visited[0] = True
curr_path[0] = 0
# Driver code
N=4
final_path = [None] * (N + 1)
visited = [False] * N
# of shortest tour.
final_res = maxsize
TSP(adj)
Minimum cost : 80
Path Taken : 0 1 3 2 0
RESULT:
Thus the above Traveling Salesman Problem by Branch and Bound technique is
executed and verified successfully.
ASSIGNMENT PROBLEM
AIM:
ALGORITHM:
STEP 1: Start with a cost matrix representing the cost of assigning workers to tasks.
STEP 4: Cover as many zeros as possible with the minimum number of horizontal and
vertical lines. If all zeros are covered, go to Step 8.
STEP 6: Subtract this smallest uncovered element from all uncovered rows and add it to all
covered columns.
STEP 8: Use the lines to determine the optimal assignment. Assign tasks to workers based on
the lines drawn.
STEP 9:Output the optimal assignments, which represent the optimal solution to the
assignment problem.
PROGRAM
import numpy as np
def assign(cost_matrix):
n = len(cost_matrix)
# Step 1: Subtract the minimum value in each row from the row
for i in range(n):
min_val = min(cost_matrix[i])
cost_matrix[i] -= min_val
# Step 2: Subtract the minimum value in each column from the column
for j in range(n):
min_val = min(cost_matrix[:, j])
cost_matrix[:, j] -= min_val
for i in range(n):
for j in range(n):
if cost_matrix[i, j] == 0 and not row_covered[i] and not col_covered[j]:
mask[i, j] = True
row_covered[i] = True
col_covered[j] = True
row_covered[:] = False
col_covered[:] = False
for i in range(n):
if not row_covered[i]:
for j in range(n):
if not col_covered[j]:
if (cost_matrix[i, j] < min_val) and (not mask[i, j]):
min_val = cost_matrix[i, j]
for i in range(n):
if row_covered[i]:
for j in range(n):
cost_matrix[i, j] += min_val
if col_covered[j]:
for i in range(n):
cost_matrix[i, j] -= min_val
min_lines = 0
for i in range(n):
if row_covered[i]:
min_lines += 1
if col_covered[j]:
min_lines += 1
row_covered[:] = False
col_covered[:] = False
# Step 5: Find the smallest uncovered element and subtract it from uncovered rows
min_val = np.inf
for i in range(n):
if not row_covered[i]:
for j in range(n):
if not col_covered[j]:
if cost_matrix[i, j] < min_val:
min_val = cost_matrix[i, j]
for i in range(n):
if not row_covered[i]:
cost_matrix[i, :] -= min_val
if col_covered[j]:
cost_matrix[:, j] += min_val
# Step 6: Find the minimum number of lines to cover all zeros again
min_lines = min(n, n)
for i in range(n):
if not row_covered[i]:
for j in range(n):
if not col_covered[j]:
if (cost_matrix[i, j] < min_val) and (not mask[i, j]):
min_val = cost_matrix[i, j]
for i in range(n):
if row_covered[i]:
for j in range(n):
cost_matrix[i, j] += min_val
if col_covered[j]:
for i in range(n):
cost_matrix[i, j] -= min_val
min_lines = 0
for i in range(n):
if row_covered[i]:
min_lines += 1
if col_covered[j]:
min_lines += 1
row_covered[:] = False
col_covered[:] = False
for i in range(n):
for j in range(n):
if mask[i, j]:
assignments[i, 0] = i
assignments[i, 1] = j
return assignments
# Example usage:
cost_matrix = np.array([[10, 19, 8, 15],
[10, 18, 7, 17],
[13, 16, 9, 14],
[12, 19, 8, 18]])
assignments = assign(cost_matrix)
print("Assignments:")
print(assignments)
OUTPUT:
Assignments:
[[0 0]
[1 2]
[2 1]
[0 0]]
RESULT:
Thus the program was executed successfully and output was verified.