Daa Lab Manual
Daa Lab Manual
Name:-
Reg.No.:-
Department:-
Semester:-
Subject Name:-
Subject Code:-
5 Dynamic programming -
Coinchange Problem, Warshall’s
and Floyd‘s algorithms,Knapsack
Problem
Aim: To study the order of growth from log2(n) to n! and implement algorithms to illustrate
this growth.
Algorithms:
1. Logarithmic Growth - O(log2(n)):
Recursive Algorithm:
1. If n is less than or equal to 1, return 0.
2. Otherwise, divide n by 2 and add 1 to the result.
3. Repeat step 2 recursively until n becomes 1 or less.
Non-Recursive Algorithm:
1. Initialize a count to 0.
2. While n is greater than 1, divide n by 2, and increment the count by 1.
3. Return the count as the result.
2. Linear Growth - O(n):
Recursive Algorithm:
1. If n is less than or equal to 1, return 1.
2. Otherwise, multiply n with the result of the recursive call for n-1.
3. Repeat step 2 recursively until n becomes 1 or less.
Non-Recursive Algorithm:
1. Initialize a result to 1.
2. For each integer i from 1 to n, multiply the result by i.
3. Return the result as the final answer.
3. Exponential Growth - O(2^n):
Recursive Algorithm:
1. If n is less than or equal to 1, return 1.
2. Otherwise, multiply 2 with the result of the recursive call for n-1.
3. Repeat step 2 recursively until n becomes 1 or less.
Non-Recursive Algorithm:
1. Initialize a result to 1.
2. For each integer i from 1 to n, multiply the result by 2.
3. Return the result as the final answer.
4. Factorial Growth - O(n!):
Recursive Algorithm:
1. If n is 0, return 1.
2. Otherwise, multiply n with the result of the recursive call for n-1.
3. Repeat step 2 recursively until n becomes 0.
Non-Recursive Algorithm:
1. Initialize a result to 1.
2. For each integer i from 1 to n, multiply the result by i.
3. Return the result as the final answer.
Program:
# Recursive Algorithm for Logarithmic Growth -
O(log2(n)) def log2_recursive(n):
if n <= 1:
return 0
return 1 + log2_recursive(n // 2)
# Non-Recursive Algorithm for Logarithmic Growth -
O(log2(n)) def log2_non_recursive(n):
count = 0
while n > 1:
n //= 2
count += 1
return count
# Recursive Algorithm for Linear Growth -
O(n) def linear_recursive(n):
if n <= 1:
return 1
return n * linear_recursive(n- 1)
# Non-Recursive Algorithm for Linear Growth -
O(n) def linear_non_recursive(n):
result = 1
for i in range(1, n +
1):result *= i
return result
# Recursive Algorithm for Exponential Growth -
O(2^n) def exponential_recursive(n):
if n <= 1:
return 1
return 2 * exponential_recursive(n- 1)
# Non-Recursive Algorithm for Exponential Growth -
O(2^n) def exponential_non_recursive(n):
result = 1
for i in
range(n):
result *= 2
return result
# Recursive Algorithm for Factorial Growth -
O(n!) def factorial_recursive(n):
if n == 0:
return 1
return n * factorial_recursive(n- 1)
# Non-Recursive Algorithm for Factorial Growth -
O(n!) def factorial_non_recursive(n):
result = 1
for i in range(1, n +
1):result *= i
return result
# Example usage:
n = 10 # You can change this value to test different n
values print(f"log2_recursive({n}) = {log2_recursive(n)}")
print(f"log2_non_recursive({n}) =
{log2_non_recursive(n)}") print(f"linear_recursive({n}) =
{linear_recursive(n)}")
print(f"linear_non_recursive({n}) = {linear_non_recursive(n)}")
print(f"exponential_recursive({n}) = {exponential_recursive(n)}")
print(f"exponential_non_recursive({n}) = {exponential_non_recursive(n)}")
print(f"factorial_recursive({n}) = {factorial_recursive(n)}")
print(f"factorial_non_recursive({n}) = {factorial_non_recursive(n)}")
Output:-
log2_recursive(10) = 3
log2_non_recursive(10) = 3
linear_recursive(10) = 3628800
linear_non_recursive(10) = 3628800
exponential_recursive(10) = 1024
exponential_non_recursive(10) = 1024
factorial_recursive(10) = 3628800
factorial_non_recursive(10) = 3628800
Result:
Implementation of recursive and non-recursive algorithms and study the order of growth
from log2n to n! Has been completed successfully.
Ex. 02 Divide and Conquer - Strassen’s Matrix Multiplication
Aim: To implement Strassen’s Matrix Multiplication using the Divide and Conquer approach
and study its efficiency compared to standard matrix multiplication for various matrix sizes.
Algorithms:
1. Input:
Two square matrices A and B of the same order (n x n).
2. Base Case:
If the size of the matrices becomes small enough (e.g., n <= a threshold),
perform a standard matrix multiplication algorithm (e.g., the naive approach).
3. Divide:
Divide matrices A and B into four equal-sized submatrices each. For example,
if A is divided into A11, A12, A21, and A22, then B is divided into B11, B12,
B21, and B22 in the same way.
4. Conquer:
Recursively compute seven products: P1, P2, P3, P4, P5, P6, and P7.
P1 = A11 * (B12- B22)
P2 = (A11 + A12) * B22
P3 = (A21 + A22) * B11
P4 = A22 * (B21- B11)
P5 = (A11 + A22) * (B11 + B22)
P6 = (A12- A22) * (B21 + B22)
P7 = (A11- A21) * (B11 + B12)
5. Combine:
Compute the resulting matrix C using the seven products:
C11 = P5 + P4- P2 + P6
C12 = P1 + P2
C21 = P3 + P4
C22 = P5 + P1- P3- P7
Program:-
import numpy as np
def strassen_matrix_multiply(A,
B): n = len(A)
# Base case: If matrices are small enough, use standard multiplication
if n <= threshold:
return np.dot(A,
B) # Divide
mid = n // 2
A11, A12 = A[:mid, :mid], A[:mid, mid:]
A21, A22 = A[mid:, :mid], A[mid:, mid:]
B11, B12 = B[:mid, :mid], B[:mid, mid:]
B21, B22 = B[mid:, :mid], B[mid:, mid:]
# Recursively compute the seven products
P1 = strassen_matrix_multiply(A11, B12-
B22) P2 = strassen_matrix_multiply(A11 +
A12, B22) P3 = strassen_matrix_multiply(A21
+ A22, B11) P4 =
strassen_matrix_multiply(A22, B21- B11)
P5 = strassen_matrix_multiply(A11 + A22, B11 +
B22) P6 = strassen_matrix_multiply(A12- A22, B21
+ B22) P7 = strassen_matrix_multiply(A11- A21,
B11 + B12) # Combine to form the result matrix
C11 = P5 + P4- P2 +
P6 C12 = P1 + P2
C21 = P3 + P4
C22 = P5 + P1- P3- P7
Output:-
[[170 180 190 200]
[426 452 478 504]
[682 724 766 808]
[938 996 1054 1112]]
Result:
Implementation of Stassen’s Matrix Multiplication using the Divide and Conquer has been
successfully completed.
Ex.03 Decrease and Conquer - Topological Sorting
Output:-
['A', 'C', 'B', 'D', 'E']
# Build a max-heap.
for i in range(n // 2- 1,-1,-1):
heapify(arr, n, i)
# Extract elements one by one and place at the end of the array. for
i in range(n- 1, 0,-1):
arr[i], arr[0] = arr[0], arr[i] # Swap
heapify(arr, i, 0)
# Example usage:
arr = [12, 11, 13, 5, 6, 7]
heap_sort(arr)
print(arr)
Output:-
[5, 6, 7, 11, 12, 13]
Result:-
The operation of Heap Sort has been completed successfully
Ex:- 05 Dynamic programming - Coin change Problem, Warshall’s and Floyd‘s algorithms,
Knapsack Problem
Aim:- Find the minimum number of coins required to make change for a given amount
using a given set of coin denominations.
Algorithm:
Initialize a list dp of size amount + 1, where dp[i] represents the minimum number
of coins needed to make change for i amount.
Set dp[0] to 0, as zero coins are needed to make change for 0 amount.
Iterate through each coin denomination and update dp using the minimum
number of coins for each amount from 1 to amount.
Return dp[amount] as the minimum number of coins needed, or-1 if change is not
possible.
Program:-
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i- coin] + 1)
return dp[amount] if dp[amount] != float('inf') else-1
# Example usage:
coins = [1, 2, 5]
amount = 11
result = coin_change(coins, amount)
print(result)
output:- the minimum number of coins needed to make change for 11 is 3 (two 5-coins
and one 1-coin).
2. Warshall's Algorithm:
Aim: Find the transitive closure of a directed graph, determining if there is a path
between every pair of vertices in the graph.
Algorithm:
Initialize the distance matrix as the adjacency matrix of the graph.
For each vertex k, consider all pairs of vertices (i, j) and update the distance matrix
with the minimum distance from i to j via vertex k.
Repeat this process for all vertices k.
The resulting matrix represents the transitive closure, where dist[i][j] is 1 if there is
a path from vertex i to vertex j, and 0 otherwise.
Program:-
def floyd_warshall(graph):
n = len(graph)
for k in
range(n):
for i in range(n):
for j in range(n):
graph[i][j] = min(graph[i][j], graph[i][k] +
graph[k][j])return graph
# Example usage:
inf = float('inf')
graph = [[0, 3, inf, inf],
[2, 0, inf, inf],
[inf, 7, 0, 1],
[6, inf, inf, 0]]
result =
floyd_warshall(graph)
print(result)
output:-
The resulting matrix represents the shortest path distances between all pairs of vertices in
the graph.
3. Knapsack Problem
Aim: Determine the maximum total value that can be obtained by selecting a subset of
items with weights and values, such that their total weight doesn't exceed a given
knapsack
capacity.
Algorithm:
Create a 2D table dp of size (n + 1) x (capacity + 1), where dp[i][w] represents the
maximum value that can be obtained using the first i items and a knapsack
capacity of w.
Fill in the table using dynamic programming, considering the choices of including
or excluding each item.
The final value in dp at dp[n][capacity] will represent the maximum value that can
be obtained.
Program:-
def knapsack(items, capacity):
n = len(items)
dp = [[0] * (capacity + 1) for _ in range(n +
1)] for i in range(1, n + 1):
for w in range(1, capacity + 1):
weight, value = items[i-
1]if weight <= w:
dp[i][w] = max(dp[i- 1][w], dp[i- 1][w- weight] +
value)else:
dp[i][w] = dp[i-
1][w]return dp[n][capacity]
# Example usage:
items = [(2, 12), (1, 10), (3, 20), (2, 15)]
capacity = 5
result = knapsack(items,
capacity) print(result)
Output:- he maximum total value that can be obtained with a knapsack capacity of 5 is 37
Result:- The operation of Coin change Problem, Warshall’s and Floyd‘s algorithms, Knapsack
Problem has been completed successfully.
Ex.-06 Greedy Technique – Dijkstra’s algorithm, Huffman Trees and codes
1. Dijkstra’s algorithms
Aim: Find the shortest path from a source vertex to all other vertices in a
weighted graph.
Algorithm:
Start with a distance array, initially set to infinity for all vertices except thesource
vertex, which is set to 0.
Maintain a set of unvisited vertices.
While there are unvisited vertices, select the vertex with the smallest distance from the
source.
Update the distances of its neighbors if a shorter path is found.
Repeat the process until all vertices have been visited.
Program:-
import heapq
def dijkstra(graph, start):
# Initialize distance to all vertices as infinity distances =
{vertex: float('infinity') for vertex in graph}
distances[start] = 0
priority_queue = [(0, start)]
while priority_queue:
current_distance, current_vertex = heapq.heappop(priority_queue)if
current_distance > distances[current_vertex]:
continue
for neighbor, weight in graph[current_vertex].items():
distance = current_distance + weight
# If a shorter path is found, update the distance and priority queue.if
distance < distances[neighbor]:
distances[neighbor] = distance heapq.heappush(priority_queue,
(distance, neighbor))
return distances
graph = {
'A': {'B': 1, 'C': 4},
'B': {'A': 1, 'C': 2, 'D': 5},
'C': {'A': 4, 'B': 2, 'D': 1},
'D': {'B': 5, 'C': 1}
}
start_vertex = 'A'
result = dijkstra(graph, start_vertex)
print(result)
output:-
{'A': 0, 'B': 1, 'C': 3, 'D': 4}
2. Huffman Trees and Codes:
Aim: Construct an optimal binary tree for encoding and decoding data, where frequentlyused
symbols have shorter codes and less frequently used symbols have longer codes.
Algorithm:
Create a list of nodes, each representing a symbol and its frequency.
Build a priority queue (min-heap) using the list of nodes.
Repeatedly merge the two nodes with the lowest frequencies into a new node,updating
the frequency.
Continue this process until a single tree is formed.
Assign binary codes to the tree's edges, where left edges are assigned '0' and rightedges '1'.
Program:-
import heapq
from collections import defaultdict def
build_huffman_tree(symbols):.
heap = [(freq, [sym, ""]) for sym, freq in symbols.items()]
heapq.heapify(heap)
while len(heap) > 1:
# Remove the two nodes with the lowest frequencies.freq1,
node1 = heapq.heappop(heap)
freq2, node2 = heapq.heappop(heap)
merged_freq = freq1 + freq2
merged_node = [node1, node2]
heapq.heappush(heap, (merged_freq, merged_node))def
generate_huffman_codes(tree, prefix="", codes=None):
if codes is None:
codes = {}
if len(tree) == 1:
symbol, _ = tree[0]
codes[symbol] = prefix
else:
left, right = tree
generate_huffman_codes(left, prefix + "0", codes)
generate_huffman_codes(right, prefix + "1", codes)
return codes
# Example usage:
symbols = {'A': 5, 'B': 9, 'C': 12, 'D': 13, 'E': 16, 'F': 45}
huffman_tree = build_huffman_tree(symbols) huffman_codes =
generate_huffman_codes(huffman_tree)print(huffman_codes)
Output:-
{'A': '1100', 'B': '1101', 'C': '100', 'D': '101', 'E': '111', 'F': '0'}
Result:-
Implementation of Dijkstra’s algorithm, Huffman Trees and codes has been completed
successfully.
Ex. 07 Iterative improvement - Simplex Method
Aim: Solve linear programming problems to optimize a linear objective function subjectto linear
equality and inequality constraints.
Algorithm:
1. Start with an initial feasible solution. This is typically achieved by introducing slack or
surplus variables.
2. While there exists a pivot element in the current tableau (indicating that the current solution
isn't optimal): a. Select a pivot column (usually the one with the most negative coefficient in
the objective function). b. Select a pivot row (the one with thesmallest non-negative ratio
between the right-hand side and the pivot column's coefficients). c. Update the tableau by
applying the pivot operation, which involves making the pivot element 1 and updating the
other elements in the pivot column androw. d. Repeat steps (a) to (c) until no more pivot
elements can be found.
3. The final tableau represents the optimal solution to the linear programming problem.Extract
the optimal values of decision variables from the tableau.
Program:-
from scipy.optimize import linprog
# Define the coefficients of the objective function.c =
[-3, -2]
# Define the coefficients of the inequality constraints.A = [
[1, 1],
[2, 1]
]
# Define the right-hand side of the inequality constraints.b =
[4, 5]
# Define the bounds for decision variables (default is non-negative).
x_bounds = (0, None)
y_bounds = (0, None)
# Use SciPy's linprog to solve the linear programming problem. result =
linprog(c, A_ub=A, b_ub=b, bounds=[x_bounds, y_bounds])
print("Optimal Solution:")
print("x =", result.x[0])
print("y =", result.x[1])
print("Optimal Value of Objective Function:", -result.fun)
Output:-
Optimal Solution:
x = 1.0
y = 3.0
Optimal Value of Objective Function: 7.0
1. N-Queens Problem:
Aim: Place N chess queens on an N×N chessboard so that no two queens threateneach other.
Algorithm:
1. Start in the leftmost column.
2. If all queens are placed, return true.
3. Try all rows in the current column. For each row, do the following: a. If the queen canbe
placed safely in this row and column, mark this cell and recursively check the nextcolumn. b.
If the recursive call returns true, return true. c. If placing the queen in this row and column
leads to a solution, return true.
4. If no row can be safely placed, return false to trigger backtracking.
Program:-
def is_safe(board, row, col, n):
# Check if there is a queen in the current row to the leftfor i
in range(col):
if board[row][i] == 1:
return False
for i, j in zip(range(row, -1, -1), range(col, -1, -1)):if
board[i][j] == 1:
return False
for i, j in zip(range(row, n, 1), range(col, -1, -1)):if
board[i][j] == 1:
return False
return True
def solve_n_queens(n):
board = [[0] * n for _ in range(n)]
if not solve_n_queens_util(board, 0, n):
return "No solution exists."
return board
def solve_n_queens_util(board, col, n):if
col >= n:
return True
for i in range(n):
if is_safe(board, i, col, n):
board[i][col] = 1
if solve_n_queens_util(board, col + 1, n):
return True
board[i][col] = 0
return False
Outpur:-
[0, 1, 0, 0]
[0, 0, 0, 1]
[1, 0, 0, 0]
[0, 0, 1, 0]
Result:-
Implementation of N-Queen problem, Subset Sum Problem has been completed
Successfully .
Ex. 09 Branch and Bound - Assignment problem, Traveling Salesman Problem
Output:-
Minimum Distance: 85
Result:-
Implementation of Assignment problem, Traveling Salesman ProbleHas
been completed successfully.
.