Ad3351-Staff-Lab-Manual II AIDS
Ad3351-Staff-Lab-Manual II AIDS
DEPARTMENT OF
ARTIFICIAL INTELLIGENCE & DATA SCIENCE
AD3351
DESIGN AND ANALYSIS OF ALGORITHMS
LABORATORY
Semester III
Lab Manual
Regulation 2021
TABLE OF CONTENTS
6 Advance Experiments
VISION
To develop students with intellectual curiosity and technical expertise to meet the
global needs.
MISSION
To develop AI professionals of international relevance to meet the industry and societal needs
with future technologies.
MISSION
To collaborate with industry and provide the state-of-the-art infrastructural facilities, with a
conducive teaching-learning ambience.
To instill in the students the knowledge for world class technical competence, entrepreneurial
skill and a spirit of innovation in the area of Artificial Intelligence and Data Science to solve real
world problems.
To encourage students to pursue higher education and research.
To inculcate right attitude with discipline and develop industry ready professionals for serving
the society.
LIST OF EXPERIMENTS
1. Implement recursive and non-recursive algorithms and study the order of growth from log2n
to n!.
2. Divide and Conquer - Strassen’s Matrix Multiplication
3. Decrease and Conquer - Topological Sorting
4. Transform and Conquer - Heap Sort
5. Dynamic programming - Coin change Problem, Warshall’s and Floyd‘s algorithms,
Knapsack Problem
6. Greedy Technique – Dijkstra’s algorithm, Huffman Trees and codes
7. Iterative improvement - Simplex Method
8. Backtracking – N-Queen problem, Subset Sum Problem
9. Branch and Bound - Assignment problem, Traveling Salesman Problem
TOTAL: 30 PERIODS
OUTCOMES:
CO2: Analyze the efficiency of brute force, divide and conquer, decrease and conquer, Transformand conquer
algorithmic techniques
CO3: Implement and analyze the problems using dynamic programming and greedy algorithmic techniques.
CO4: Solve the problems using iterative improvement techniques for optimization.
CO5: Compute the limitations of algorithmic power and solve the problems using backtracking and branch
and bound techniques.
Course Outcomes
After completion of the course, Students are able to learn the listed Course Outcomes.
Knowledge
Cos Course Outcomes
Level
Analyze the efficiency of recursive and non-recursive algorithms
CO1 K2
mathematically
Analyze the efficiency of brute force, divide and conquer, decrease and
CO2 K3
conquer, Transform and conquer algorithmic techniques
Implement and analyze the problems using dynamic programming and
CO3 K3
greedy algorithmic techniques.
Solve the problems using iterative improvement techniques for
CO4 K2
optimization.
Compute the limitations of algorithmic power and solve the problems
CO5 K4
using backtracking and branch and bound techniques.
List of Experiments with COs, POs and PSOs
Exp.
Name of the Experiment COs POs PSOs
No.
Implement recursive and non-recursive
1 algorithms and study the order of growth CO1 PO1,2 PSO1,2,3
from log2n to n!.
Divide and Conquer - Strassen’s Matrix CO2 PO1,2 PSO1,2,3
2
Multiplication
Decrease and Conquer - Topological CO2 PO1,2 PSO1,2,3
3
Sorting
4 Transform and Conquer - Heap Sort CO2 PO1,2 PSO1,2,3
Dynamic programming - Coin change CO3 PO1,2 PSO1,2,3
5 Problem, Warshall’s and Floyd‘s
algorithms, Knapsack Problem
Greedy Technique – Dijkstra’s algorithm, CO3 PO1,2 PSO1,2,3
6
Huffman Trees and codes
7 Iterative improvement - Simplex Method CO4 PO1,2 PSO1,2,3
Backtracking – N-Queen problem, Subset CO5 PO1,2 PSO1,2,3
8
Sum Problem
Branch and Bound - Assignment problem, CO5 PO1,2 PSO1,2,3
9
Traveling Salesman Problem
Additional Experiments
Implement linear search. Determine the CO1 PO1,2 PSO1,2,3
10
time required to search for an element.the
6
Program Outcomes
1. Engineering Knowledge 7. Environment and Sustainability
2. Problem Analysis 8. Ethics
3. Design/Development of Solutions 9. Individual and Team Work
4. Conduct Investigations of Complex Problems 10. Communication
5. Modern Tool Usage 11. Project Management and Finance
6. The Engineer and Society 12. Life-long Learning
AIM:
The aim is to implement recursive and non-recursive algorithms and
study the order of growth from log 2N to n!
ALGORTIHM:
Step 1: Start the program.
Step 2: Implement Recursive and non-recursive algorithm using log 2n to n!
Step 3: compute the factorial n* fact (n-1), Fibonacci Series using recursive
algorithm.
Step 4: Iterate from 1 to n, multiplying the current value by the iterator using non-
recursive algorithm.
Step 5: End the program.
PROGRAM:
import time
import math
# Recursive Algorithm
def recursive_factorial(n):
if n == 0 or n == 1:
return 1
return n * recursive_factorial(n - 1)
# Non-Recursive Algorithm
def non_recursive_factorial(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
Page | 9
OUTPUT:
n = 2^1
Recursive Time: 6.9141387939453125e-06
Non-Recursive Time: 2.86102294921875e-06
n = 2^2
Recursive Time: 1.1920928955078125e-05
Non-Recursive Time: 4.76837158203125e-06
n = 2^3
Recursive Time: 1.6927719116210938e-05
Non-Recursive Time: 5.7220458984375e-06
n = 2^4
Recursive Time: 2.9802322387695312e-05
Non-Recursive Time: 7.152557373046875e-06
n = 2^5
Recursive Time: 5.698204040527344e-05
Non-Recursive Time: 1.0013580322265625e-05
RESULT:
Thus, the recursive and non-recursive algorithms for various functions and
study their order of growth was implemented successfully.
Page | 10
AIM:
To implement Strassen’s Matrix Multiplication using the Divide and
Conquer approach and demonstrate its application on directed acyclic graphs
(DAGs).
ALGORTIHM:
Step 1: Start the program.
Step 2: Create the matrix A&B.
Step 3: Divide the matrix A & matrix B into 4 sub-matrices of size n/2*n/2.
Step 4: Calculate the strassen’s matrix multiplication recursively.
Step 5: Compute the submatrices of C.
Step 6: Combine the submatrices into our new matrix C.
Step 7: End the program.
PROGRAM:
import numpy as np
def strassen_multiply(A, B):
n = len(A)
# Base case: If the matrices are 1x1, perform standard multiplication
if n == 1:
return np.array([[A[0][0] * B[0][0]]])
# Split matrices into four equal-sized submatrices
a11 = A[:n//2, :n//2]
a12 = A[:n//2, n//2:]
a21 = A[n//2:, :n//2]
a22 = A[n//2:, n//2:]
b11 = B[:n//2, :n//2]
b12 = B[:n//2, n//2:]
b21 = B[n//2:, :n//2]
b22 = B[n//2:, n//2:]
# Recursive computation of seven products
p1 = strassen_multiply(a11 + a22, b11 + b22)
p2 = strassen_multiply(a21 + a22, b11)
p3 = strassen_multiply(a11, b12 - b22)
p4 = strassen_multiply(a22, b21 - b11)
p5 = strassen_multiply(a11 + a12, b22)
p6 = strassen_multiply(a21 - a11, b11 + b12)
p7 = strassen_multiply(a12 - a22, b21 + b22)
# Combine the products to get the result matrix
c11 = p1 + p4 - p5 + p7
Page | 11
c12 = p3 + p5
c21 = p2 + p4
c22 = p1 - p2 + p3 + p6
# Combine the submatrices into the result matrix
result = np.vstack((np.hstack((c11, c12)), np.hstack((c21, c22))))
return result
# Main program
if __name__ == "__main__":
# Example matrices A and B
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Perform Strassen's Matrix Multiplication
result = strassen_multiply(A, B)
# Display the result
print("Matrix A:")
print(A)
print("\nMatrix B:")
print(B)
print("\nResultant Matrix C (Strassen's Multiplication):")
print(result)
Page | 12
OUTPUT:
Matrix A:
[[1 2]
[3 4]]
Matrix B:
[[5 6]
[7 8]]
RESULT:
Thus, the Strassen’s Matrix Multiplication using the Divide and Conquer
approach was implemented successfully.
Page | 13
AIM:
To implement Topological Sorting using the Decrease and Conquer
approach in Python and analyze its performance.
ALGORTIHM:
1. Compute In-Degrees:
For each vertex in the graph, compute its in-degree (the number of incoming
edges).
2. Find Vertices with In-Degree of 0:
Identify all vertices with an in-degree of 0. These are the vertices with no
incoming edges.
3. Decrease and Conquer:
While there are vertices with an in-degree of 0:
Choose a vertex with an in-degree of 0.
Output that vertex and remove it from the graph, along with its outgoing edges.
Update the in-degree of the remaining vertices connected to the removed
vertex.
Repeat this process until all vertices are removed.
4. Check for Cycles:
After all vertices have been processed, check if the topological order contains
all vertices.
if not, the graph contains a cycle and topological sorting is not possible.
5. Output:
Return the topologically sorted order of vertices.
Page | 14
PROGRAM:
from collections import defaultdict
class Graph:
def __init__(self, vertices):
self.vertices = vertices
self.graph = defaultdict(list)
def add_edge(self, u, v):
self.graph[u].append(v)
def topological_sort_util(self, v, visited, stack):
visited[v] = True
for neighbor in self.graph[v]:
if not visited[neighbor]:
self.topological_sort_util(neighbor, visited, stack)
stack.append(v)
def topological_sort(self):
visited = [False] * self.vertices
stack = []
for i in range(self.vertices):
if not visited[i]:
self.topological_sort_util(i, visited, stack)
return stack[::-1]
# Main program
if __name__ == "__main__":
# Create a graph
g = Graph(6)
g.add_edge(5, 2)
g.add_edge(5, 0)
g.add_edge(4, 0)
g.add_edge(4, 1)
g.add_edge(2, 3)
g.add_edge(3, 1)
# Perform Topological Sorting
result = g.topological_sort()
# Display the result
print("Topological Sorting Order:")
print(result)
Page | 15
OUTPUT:
Topological Sorting Order:
[5, 4, 2, 3, 1, 0]
RESULT:
Thus, the Topological Sorting using the Decrease and Conquer approach was
implemented successfully.
Page | 16
AIM:
To implement Heap Sort using the Transform and Conquer approach in
Python and analyze performance.
ALGORTIHM:
Step 1: Start the program.
Step 2: Transform the input array into a max-heap.
Step 3: Repeatedly extract the maximum element (root of the heap) and swap it with
the last element of the heap.
Step 4: Reduce the heap size by 1 and heapify the remaining elements.
Step 5: Repeat the process until the heap is empty.
Step 6: End the program.
PROGRAM:
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heap_sort(arr):
n = len(arr)
# Step 1: Build Max Heap
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
# Step 2 to 4: Transfer and Restore
for i in range(n - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # Transfer max element
heapify(arr, i, 0) # Restore heap property
# Step 5: Output Sorted Array
return arr
# Example usage
arr = [12, 11, 13, 5, 6, 7]
print("Input Array:", arr)
print("Sorted Array:", heap_sort(arr))
Page | 17
OUTPUT:
Input Array: [12, 11, 13, 5, 6, 7]
Sorted Array: [5, 6, 7, 11, 12, 13]
RESULT:
Thus, the Heap Sort using the Transform and Conquer
approach was implemented successfully.
Page | 18
AIM:
To implement the Coin Change Problem using dynamic
programming approach in Python.
ALGORTIHM:
Step 1: Start the program.
Step 2: Create a table to store the solutions to subproblems.
Step 3: Initialize the table with base cases.
Step 4: Fill in the table using the recurrence relation.
Step 5: The final value in the table represents the solution to the original problem
Step 6: End the program.
PROGRAM:
Page | 19
OUTPUT:
RESULT:
Thus, the Coin Change Problem using dynamic programming approach
was implemented successfully.
Page | 20
AIM:
To implement the Warshall’s and Floyd’s Algorithm usin dynamic
programming approach in Python.
ALGORTIHM:
Step 1: Initialization:
Initialize a matrix dist with the same dimensions as the adjacency matrix,
initialized with the distances between vertices (dist[i][j] = weight of edge (i,
j)). Initialize diagonal elements (dist[i][i]) to 0.
Step 2: Dynamic Programming:
For each intermediate vertex k:
For each pair of vertices (i, j):
If vertex k is on the shortest path from vertex i to j, update dist[i][j] to
min(dist[i][j], dist[i][k] + dist[k][j]).
Step 3: Output:
The dist matrix contains the shortest path distances between all pairs of
vertices.
PROGRAM:
def floyd_warshall(graph):
n = len(graph)
dist = [[0 if i == j else graph[i][j] if graph[i][j] != float('inf') else float('inf') for j in
range(n)] for i in range(n)]
for k in range(n):
for i in range(n):
for j in range(n):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
# Example usage
graph = [
[0, 3, float('inf'), 7],
[8, 0, 2, float('inf')],
[5, float('inf'), 0, 1],
[2, float('inf'), float('inf'), 0]
]
shortest_paths = floyd_warshall(graph)
for row in shortest_paths:
print(row)
Page | 21
OUTPUT:
[0, 3, 5, 6]
[5, 0, 2, 3]
[3, 6, 0, 1]
[2, 5, 7, 0]
RESULT:
Thus, the Warshall’s and Floyd’s Algorithm using dynamic programming
approach was implemented successfully.
Page | 22
AIM:
To implement the Knapsack Problem using dynamic programming approach in
Python.
ALGORTIHM:
Step 1: Initialization:
Create a 2D array dp[][] with dimensions (n+1) x (W+1), where n is the number of
items and W is the capacity of the knapsack. Initialize the array with zeros.
Step 2: Dynamic Programming:
Iterate over each item from 1 to n and each capacity from 1 to W.
For each item i and capacity w:
If the weight of the current item is less than or equal to the current capacity,
choose the maximum value between:
The value of selecting the current item plus the value of the best solution for the
remaining capacity (dp[i-1][w - weights[i-1]]).
The value of not selecting the current item (dp[i-1][w]).
Otherwise, the value remains the same as the value obtained without considering
the current item (dp[i-1][w]).
Step 3: Output:
The value of dp[n][W] represents the maximum value that can be obtained by
selecting items to fit into the knapsack.
Page | 23
PROGRAM:
def knapsack(W, weights, values):
n = len(weights)
dp = [[0] * (W + 1) for _ in range(n + 1)]
Page | 24
OUTPUT:
RESULT:
Thus, the Knapsack Problem using dynamic programming approach
was implemented successfully.
Page | 25
AIM:
To implement Dijkstra's Algorithm using Greedy Technique in Python for
finding the shortest path in a weighted graph.
ALGORTIHM:
Step 1: Initialize the distance of all vertices from the source as infinity, and
the distance of the source vertex to itself as 0.
Step 2: Create a priority queue to store vertices and their distances.
Step 3: While the priority queue is not empty, extract the vertex with the
minimum distance.
Step 4: Update the distances of adjacent vertices if a shorter path is found.
Step 5: Repeat until all vertices are processed.
PROGRAM:
import heapq
def dijkstra(graph, source):
n = len(graph)
distances = [float('inf')] * n
distances[source] = 0
visited = [False] * n
pq = [(0, source)] # (distance, vertex)
while pq:
dist_u, u = heapq.heappop(pq)
if visited[u]:
continue
visited[u] = True
for v, weight in graph[u]:
if not visited[v] and dist_u + weight < distances[v]:
distances[v] = dist_u + weight
heapq.heappush(pq, (distances[v], v))
return distances
graph = {
0: [(1, 4), (2, 2)],
1: [(2, 5), (3, 10)],
2: [(3, 3)],
3: []
}
source = 0
print("Shortest distances from source vertex", source, ":", dijkstra(graph, source)
Page | 26
OUTPUT:
RESULT:
Thus, the Dijkstra's Algorithm using Greedy Technique was implemented
successfully.
Page | 27
AIM:
To implement Huffman tree and codes using Greedy Technique in Python for finding
the shortest path in a weighted graph.
ALGORTIHM:
Step 1: Create a leaf node for each unique character and build a min heap of
all leaf nodes (Min Heap is used as a priority queue. The value of frequency
field is used to compare two nodes in min heap. Initially, the least frequent
character is at root)
Step 2: Extract two nodes with the minimum frequency from the min heap.
Step 3: Create a new internal node with a frequency equal to the sum of the
two nodes frequencies. Make the first extracted node as its left child and the
other extracted node as its right child. Add this node to the min heap.
Step 4: Repeat steps#2 and #3 until the heap contains only one node. The
remaining node is the root node and the tree is complete.
PROGRAM:
import heapq
from collections import defaultdict
class Node:
def __init__(self, freq, symbol=None):
self.freq = freq
self.symbol = symbol
self.left = None
self.right = None
def __lt__(self, other):
return self.freq < other.freq
def build_huffman_tree(symbols_freq):
pq = [Node(freq, symbol) for symbol, freq in symbols_freq.items()]
heapq.heapify(pq)
while len(pq) > 1:
left = heapq.heappop(pq)
right = heapq.heappop(pq)
merged = Node(left.freq + right.freq)
merged.left = left
merged.right = right
heapq.heappush(pq, merged)
Page | 28
return pq[0]
def generate_huffman_codes(root, prefix="", codes={}):
if root is None:
return
if root.symbol is not None:
codes[root.symbol] = prefix
generate_huffman_codes(root.left, prefix + "0", codes)
generate_huffman_codes(root.right, prefix + "1", codes)
# Example usage
symbols_freq = {'A': 5, 'B': 9, 'C': 12, 'D': 13, 'E': 16, 'F': 45}
huffman_tree = build_huffman_tree(symbols_freq)
huffman_codes = {}
generate_huffman_codes(huffman_tree, "", huffman_codes)
print("Huffman Codes:")
for symbol, code in huffman_codes.items():
print(symbol, ":", code)
Page | 29
OUTPUT:
Huffman Codes:
A : 1100
B : 1101
C : 100
D : 101
E : 111
F:0
RESULT:
Thus, the Huffman tree and codes using Greedy Technique was
implemented successfully.
Page | 30
AIM:
To implement the Simplex Method using Iterative Improvement in Python for solving
linear programming problems.
ALGORTIHM:
Step 1: Formulate the initial tableau.
Step 2: Iterate through the tableau until an optimal solution is found or it is
determined that the solution is unbounded.
Step 3: Choose a pivot column and pivot row.
Step 4: Update the tableau using pivot operations.
Step 5: Repeat until an optimal solution is achieved.
PROGRAM:
import numpy as np
def simplex_method(c, A, b):
m, n = A.shape
tableau = np.hstack((A, np.eye(m)))
c = np.hstack((c, np.zeros(m)))
basic_vars = np.arange(n, n + m)
while True:
# Check if the current solution reaches the optimal solution
if np.all(c <= 0):
optimal_solution = tableau[:-1, -1]
optimal_value = -tableau[-1, -1]
return optimal_solution[:n], optimal_value
# Choose the pivot column (minimum coefficient in the objective function)
pivot_col = np.argmin(c)
# Check for unbounded solution
if np.all(tableau[:, pivot_col] <= 0):
raise Exception("The solution is unbounded.")
# Choose the pivot row (minimum ratio test)
ratios = tableau[:-1, -1] / tableau[:-1, pivot_col]
pivot_row = np.argmin(ratios)
# Update the tableau using pivot operations
pivot = tableau[pivot_row, pivot_col]
tableau[pivot_row, :] /= pivot
Page | 31
Page | 32
OUTPUT:
RESULT:
Thus, the Simplex Method using Iterative Improvement was
implemented successfully.
Page | 33
AIM:
To implement the N-Queen Problem using the Backtracking algorithm in
Python.
ALGORTIHM:
The N-Queen problem is to place N chess queens on an \(N \times N\)
chessboard in such a way that no two queens threaten each other.
Step 1: Start with an empty chessboard.
Step 2: Place queens one by one in different columns, starting from the
leftmost column.
Step 3: Check if the current placement is safe. If not, backtrack and try the
next position.
Step 4: Repeat the process until all queens are placed or it's determined
that no solution exists.
PROGRAM:
def is_safe(board, row, col, N):
for i in range(row):
if board[i][col] == 1:
return False
# Check upper left diagonal
for i, j in zip(range(row, -1, -1), range(col, -1, -1)):
if board[i][j] == 1:
return False
# Check upper right diagonal
for i, j in zip(range(row, -1, -1), range(col, N)):
if board[i][j] == 1:
return False
return True
def solve_n_queens_util(board, row, N):
if row == N:
return True
for col in range(N):
if is_safe(board, row, col, N):
board[row][col] = 1
if solve_n_queens_util(board, row + 1, N):
return True
board[row][col] = 0
Page | 34
return False
def solve_n_queens(N):
board = [[0] * N for _ in range(N)]
if solve_n_queens_util(board, 0, N):
return board
else:
return None
def print_board(board):
for row in board:
print(" ".join(str(cell) for cell in row))
N=4
solution = solve_n_queens(N)
if solution:
print("Solution for {}-Queens Problem:".format(N))
print_board(solution)
else:
print("No solution exists for {}-Queens Problem.".format(N))
Page | 35
OUTPUT:
RESULT:
Thus,the N-Queen Problem using the Backtracking algorithm was implemented
successfully.
Page | 36
AIM:
To implement the Subset Sum Problem using the Backtracking algorithm in
Python.
ALGORTIHM:
Given a set of positive integers and a target sum, determine if there is a subset
of the set that adds up to the target sum.
Step 1: Start with an empty subset.
Step 2: Include an element in the subset and recursively check if the
remaining sum can be obtained.
Step 3: Exclude the element from the subset and recursively check if the sum
can be obtained without the element.
Step 4: Repeat the process for each element in the set.
PROGRAM:
def subset_sum_util(nums, target, current_sum, start, path, result):
if current_sum == target:
result.append(path[:])
return
for i in range(start, len(nums)):
if current_sum + nums[i] <= target:
path.append(nums[i])
subset_sum_util(nums, target, current_sum + nums[i], i + 1, path, result)
path.pop()
def subset_sum(nums, target):
result = []
subset_sum_util(nums, target, 0, 0, [], result)
return result
# Main program
if __name__ == "__main__":
nums = [1, 2, 3, 4, 5]
target = 7
subsets = subset_sum(nums, target)
print(f"Subsets with sum equal to {target}:")
for subset in subsets:
print(subset)
Page | 37
OUTPUT:
RESULT:
Thus, the Subset Sum Problem using the Backtracking algorithm
was implemented successfully.
Page | 38
AIM:
To implement the Assignment Problem using the Branch and Bound
algorithm in Python.
ALGORTIHM:
Given a set of cities and the distances between each pair of cities, find the
shortest possible tour that visits each city exactly once and returns to the
starting city.
Step 1: Create a cost matrix for the assignment problem.
Step 2: Implement the Branch and Bound algorithm to find the optimal assignment.
PROGRAM:
import numpy as np
from itertools import permutations
def assignment_cost(assignment, cost_matrix):
total_cost = 0
for worker, task in enumerate(assignment):
total_cost += cost_matrix[worker, task]
return total_cost
def branch_and_bound_assignment(cost_matrix):
n = len(cost_matrix)
min_cost = float('inf')
optimal_assignment = None
for assignment in permutations(range(n)):
current_cost = assignment_cost(assignment, cost_matrix)
if current_cost < min_cost:
min_cost = current_cost
optimal_assignment = assignment
return optimal_assignment, min_cost
# Main program
if __name__ == "__main__":
# Example cost matrix for the assignment problem
cost_matrix = np.array([
[9, 2, 7, 8],
[6, 4, 3, 7],
[5, 8, 1, 8],
Page | 39
[7, 6, 9, 4]
])
optimal_assignment, min_cost = branch_and_bound_assignment(cost_matrix)
print("Optimal Assignment:", optimal_assignment)
print("Minimum Cost:", min_cost)
Page | 40
OUTPUT:
RESULT:
Thus, the Assignment Problem using the Branch and Bound algorithm was
implemented successfully.
Page | 41
AIM:
To implement the Traveling Salesman Problem using the Branch and
Bound algorithm in Python.
ALGORTIHM:
Given a set of cities and the distances between each pair of cities, find the
shortest possible tour that visits each city exactly once and returns to the
starting city.
Step 1: Create a distance matrix for the TSP.
Step 2: Implement the Branch and Bound algorithm to find the optimal tour.
PROGRAM:
import numpy as np
def tsp_cost(tour, distance_matrix):
total_cost = 0
for i in range(len(tour) - 1):
total_cost += distance_matrix[tour[i], tour[i + 1]]
# Add cost to return to the starting city
total_cost += distance_matrix[tour[-1], tour[0]]
return total_cost
def branch_and_bound_tsp(distance_matrix):
n = len(distance_matrix)
optimal_tour = None
min_cost = float('inf')
initial_tour = list(range(n))
Page | 43
OUTPUT:
Optimal Tour: [0, 1, 3, 2]
Minimum Cost: 80
RESULT:
Thus, the Traveling Salesman Problem using the Branch and Bound
algorithm was implemented successfully
Page | 44
AIM:
To implement linear search & determine the time required to search for an
element the number of elements in the list to be searched and plot the graph of the
time taken versus n.
ALGORTIHM:
Page | 45
plt.title(title)
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.grid(True)
plt.show()
# Define a range of values for the number of elements in the list
n_values = [100, 500, 1000, 2000, 5000]
Page | 46
OUTPUT:
RESULT
Thus the given program was executed successfully.
Page | 47
AIM:
To write a program to implement the given condition using python program.
ALGORTIHM:
Step 1: Initialization:
Initialize an empty list occurrences to store the indices of occurrences of the
pattern in the text.
Step 2: Iterate through the Text:
Iterate through the text TXT[] from index 0 to N - M.
For each index i:
Check if the substring of length M starting at index i matches the pattern PAT[].
If a match is found, add the index i to the list of occurrences.
Step 3: Output:
If the list of occurrences is not empty, print the list.
If the list of occurrences is empty, print a message indicating that the pattern was
not found in the text.
PROGRAM:
def search(PAT, TXT):
M = len(PAT)
N = len(TXT)
occurrences = []
# Iterate through the text TXT[]
for i in range(N - M + 1):
# Check if the current substring of length M matches the pattern PAT[]
j=0
while j < M:
if TXT[i + j] != PAT[j]:
break
j += 1
# If the entire pattern is found at index i, add the index to the list of occurrences
if j == M:
occurrences.append(i)
if occurrences:
print("Pattern found at indices:", occurrences)
else:
print("Pattern not found in the text")
TXT = "AABAACAADAABAABA"
PAT = "AABA"
search(PAT, TXT)
Page | 48
OUTPUT:
RESULT:
Thus the given program for function search was executed successfully.
Page | 49