0% found this document useful (0 votes)
24 views50 pages

Daa - Integrated Lab Manual

Design analysis of algorithm lab
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)
24 views50 pages

Daa - Integrated Lab Manual

Design analysis of algorithm lab
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
You are on page 1/ 50

1.

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 1: Start the process.

STEP 2:Define a non recursive function to get Fibonacci

STEP 3:Define recursive function that calls itself

STEP 4:Print the results

STEP 5:Stop

PROGRAM

NON RECURSION

# Function for nth fibonacci number - Space Optimisation

# Taking 1st two fibonacci numbers as 0 and 1

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:

# Fibonacci series using recursion


def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)

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 :

To implement Strassen’s Matrix Multiplication by Divide and Conquer technique .

ALGORITHM:

STEP 1 : Start the program

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.

STEP 6: Print the result.

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]

#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)]

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)

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 =>
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 Array =>


8 8 8 8
16 16 16 16
24 24 24 24
16 16 16 16

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:

STEP 1:Start the process.


STEP 2:Define the input graph.
STEP 3:Define recursive function to do topological sort.
STEP 4: Call the recursive helper function to store Topological Sort starting from all
vertices one by one.
STEP 4: Print the result.
STEP 5: Stop the process.

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:

Following is a Topological Sort of the given graph


542310

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:

STEP 1: Start the process.


STEP 2: Define an integer array of coins[ ] of size N representing different types of
denominations and an integer sum.
STEP 3: Define Recursive function to count the number of distinct ways to make the sum
by using n coins.

STEP 4: For each coin, there are 2 options.

 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 ).

STEP 5:The final result will be the sum of both cases.

STEP 6: Print the result.

STEP 7:Stop the process.

PROBLEM:

Coin change Problem


# Python program for the above approach
# Recursive function to count the numeber of distinct ways
# to make the sum by using n coins

def count(coins, sum, n, dp):


# Base Case
if (sum == 0):
dp[n][sum] = 1
return dp[n][sum]

# 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

# If the subproblem is previously calculated then simply return the result


if (dp[n][sum] != -1):
return dp[n][sum]

# Two options for the current coin

dp[n][sum] = count(coins, sum - coins[n - 1], n, dp) + \


count(coins, sum, n - 1, dp)

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:

To implement a program for Warshall’s and Floyd‘s algorithms using Dynamic


Programming.

ALGORITHM:

STEP 1:Start the process.

STEP 2: Define input graph matrix and initialise solution matrix.

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.

STEP 5:Add vertices to the solution after estimating shortest distance.

STEP 6:Print the result

STEP 7: Stop the process.

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
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)

# A utility function to print the solution


def printSolution(dist):
print("Following matrix shows the shortest distances\
between every pair of vertices")
for i in range(V):
for j in range(V):
if(dist[i][j] == INF):
print("%7s" % ("INF"), end=" ")
else:
print("%7d\t" % (dist[i][j]), end=' ')
if j == V-1:
print()
# 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:

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:

To implement a Knapsack Problem program using Dynamic Programming method.

ALGORITHM:

Step 1:Start the process.


Step 2: Create a table to store maximum values for different subproblems.

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.

Step 5: For each item, consider two options:

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.

Step 9: Return the maximum value.


Step 10:Stop the process.

PROGRAM:

# A Dynamic Programming based Python

# Program for 0-1 Knapsack problem

# Returns the maximum value that can

# be put in a knapsack of capacity W

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

K = [[0 for x in range(W + 1)] for x in range(n + 1)]

# Build table K[][] in bottom up manner


for i in range(n + 1):

for w in range(W + 1):

if i == 0 or w == 0:

K[i][w] = 0

elif wt[i-1] <= w:

K[i][w] = max(val[i-1] + K[i-1][w-wt[i-1]], K[i-1][w])

else:

K[i][w] = K[i-1][w]

return K[n][W]

# Driver program to test above function

val = [60, 100, 120]

wt = [10, 20, 30]

W = 50

n = len(val)

print(knapSack(W, wt, val, n))

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:

To implement a program using Dijkstra’s algorithm by Greedy Technique.

ALGORITHM:

STEP 1: Start the process.

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.

STEP 4: Mark all vertices as unprocessed.

STEP 5: Repeat the following until all vertices are processed:

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:

# Python program for Dijkstra's single

# source shortest path algorithm. The program is

# for adjacency matrix representation of the graph

class Graph():

def __init__(self, vertices):

self.V = vertices

self.graph = [[0 for column in range(vertices)]

for row in range(vertices)]

def printSolution(self, dist):

print("Vertex \t Distance from Source")


for node in range(self.V):

print(node, "\t\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 = 1e7

# Search not nearest vertex not in the

# shortest path tree

for v in range(self.V):

if dist[v] < min and sptSet[v] == False:

min = dist[v]

min_index = v

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 = [1e7] * self.V

dist[src] = 0

sptSet = [False] * self.V

for cout in range(self.V):

# Pick the minimum distance vertex from

# the set of vertices not yet processed.


# u is always equal to src in first iteration

u = self.minDistance(dist, sptSet)

# Put the minimum distance vertex in the

# shortest path tree

sptSet[u] = 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 v in range(self.V):

if (self.graph[u][v] > 0 and

sptSet[v] == False and

dist[v] > dist[u] + self.graph[u][v]):

dist[v] = dist[u] + self.graph[u][v]

self.printSolution(dist)

# Driver program

g = Graph(9)

g.graph = [[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]

g.dijkstra(0)

OUTPUT:

Vertex Distance from Source


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

RESULT:

Thus the above program using Dijkstra’s algorithm by Greedy Technique is executed and
verified successfully.
Huffman Trees and codes

AIM:

To implement a program using Huffman Trees and codes by Greedy Technique.

ALGORITHM:

STEP 1: Start the process.

STEP 2: Define the characters (symbols) and their corresponding frequencies.

STEP 3: Create an empty list to store nodes.

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:

a. Find the two nodes with the lowest frequencies.


b. Combine these two nodes into a new parent node.
c. Set the frequency of the parent node as the sum of the frequencies of its
children.
d. Repeat this process until only one node remains in the list.
STEP 6: The last remaining node in the list represents the root of the Huffman tree.

STEP 7: Traverse the Huffman tree:

a. Start from the root.


b. Assign '0' to the left branch and '1' to the right branch.
c. Recursively traverse the tree, building Huffman codes for each symbol.
STEP 8: End the process.
PROGRAM:

# A Huffman Tree Node

import heapq

class node:

def __init__(self, freq, symbol, left=None, right=None):

# frequency of symbol

self.freq = freq

# symbol name (character)

self.symbol = symbol

# node left of current node

self.left = left

# node right of current node

self.right = right

# tree direction (0/1)

self.huff = ''

def __lt__(self, nxt):

return self.freq < nxt.freq

# utility function to print huffman

# codes for all symbols in the newly

# created Huffman tree

def printNodes(node, val=''):


# huffman code for current node

newVal = val + str(node.huff)

# if node is not an edge node

# then traverse inside it

if(node.left):

printNodes(node.left, newVal)

if(node.right):

printNodes(node.right, newVal)

# if node is edge node then

# display its huffman code

if(not node.left and not node.right):

print(f"{node.symbol} -> {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)):
heapq.heappush(nodes, node(freq[x], chars[x]))

while len(nodes) > 1:

# sort all the nodes in ascending order

# based on their frequency

left = heapq.heappop(nodes)

right = heapq.heappop(nodes)

# assign directional value to these nodes

left.huff = 0

right.huff = 1

# combine the 2 smallest nodes to create

# new node as their parent

newNode = node(left.freq+right.freq, left.symbol+right.symbol, left, right)

heapq.heappush(nodes, newNode)

# Huffman Tree is ready!

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:

To implement a program Iterative improvement by Simplex Method.

ALGORITHM:

STEP 1: Start the process.

STEP 2: Define the problem inputs.

STEP 3: Create an initial tableau.

STEP 4: Set up problem type and counters.

STEP 5: Print the initial tableau.

STEP 6: Repeat until termination:

a. Calculate relative profits.


b. Check for optimality.
c. Select entering and leaving variables.
d. Calculate the pivot element.
e. Update the tableau.
f. Update basic variables and coefficients.

STEP 7: Check for specific cases:

a. Check for optimality.


b. Check for unboundedness.
c. Check for alternate solutions.

STEP 8: Print the final tableau, Z value, and basis.

STEP 9: End the process.


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 = np.array([[1, 1, 0, 1], [2, 1, 1, 0]])

# b will contain the amount of resources

b = np.array([8, 10])

# c will contain coefficients of objective function Z

c = np.array([1, 1, 0, 0])

# B will contain the basic variables that make identity matrix

cb = np.array(c[3])

B = np.array([[3], [2]])

# cb contains their corresponding coefficients in Z

cb = np.vstack((cb, c[2]))

xb = np.transpose([b])

# combine matrices B and cb

table = np.hstack((B, cb))

table = np.hstack((table, xb))

# combine matrices B, cb and xb

# finally combine matrix A to form the complete simplex table

table = np.hstack((table, A))

# change the type of table to float

table = np.array(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....")

# 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] - np.sum(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

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(np.array([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,

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)

basis.append(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)

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:

To implement a – N-Queen problem, by Backtracking technique.

ALGORITHM:

STEP 1: Begin with an empty chessboard of size N x N.

STEP 2: Start with the leftmost column (column 0).

STEP 3: For the current column:

a. Begin from the top row (row 0).


b. Try placing a queen in each row of the current column.
c. Move to the next row and repeat the placement until you find a safe spot for the
queen.
d. If you find a safe spot:
e. Place a queen in that cell.
f. Move to the next column (if not the last one) and repeat step 3.
g. If there's no safe spot for the queen in the current column:
h. Backtrack to the previous column.
i. Remove the queen from the last placed cell.
j. Find the next safe spot in the previous column and repeat step 3 from there.
k. Continue this process until you reach the rightmost column (column N-1).
l.
STEP 4: When you successfully place a queen in the rightmost column, it's a solution.Print
the current configuration of the chessboard as a valid solution.

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.

STEP 7: End the process.


PROGRAM:

N = 8 # (size of the chessboard)


def solveNQueens(board, col):
if col == N:

for row in board:


print(" ".join("Q" if cell == 1 else "." for cell in row))
print()

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

def isSafe(board, row, col):


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

board = [[0 for x in range(N)] for y in range(N)]


if not solveNQueens(board, 0):
print("No solution found")
OUTPUT:

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:

To implement Traveling Salesman Problem by Branch and Bound technique.

ALGORITHM:

STEP 1: Start the process.

STEP 2: Define the distances between cities using an adjacency matrix adj and specify the
number of cities N.

STEP 3: Initialize the minimum cost as positive infinity.

STEP 4: Create an array to store the current path.

STEP 5: Create an array to keep track of visited cities.

STEP 6: Define a function to compute the minimum edge cost from a given city.

STEP 7: Define a recursive function to explore the search space.

STEP 8: Compute an initial lower bound for the root node.

STEP 9: Start the TSP recursion from the first city.

STEP 10: Print the minimum cost and the path taken.

STEP 11: End the process.


PROGRAM:

Traveling Salesman Problem

# Python3 program to solve

# Traveling Salesman Problem using

# Branch and Bound.

import math

maxsize = float('inf')

# Function to copy temporary solution

# to the final solution

def copyToFinal(curr_path):

final_path[:N + 1] = curr_path[:]

final_path[N] = curr_path[0]

# Function to find the minimum edge cost

# having an end at the vertex i

def firstMin(adj, i):

min = maxsize

for k in range(N):

if adj[i][k] < min and i != k:

min = adj[i][k]

return min

# function to find the second minimum edge

# cost having an end at the vertex i


def secondMin(adj, i):

first, second = maxsize, maxsize

for j in range(N):

if i == j:

continue

if adj[i][j] <= first:

second = first

first = adj[i][j]

elif(adj[i][j] <= second and

adj[i][j] != first):

second = adj[i][j]

return second

# function that takes as arguments:

# curr_bound -> lower bound of the root node

# curr_weight-> stores the weight of the path so far

# level-> current level while moving

# in the search space tree

# curr_path[] -> where the solution is being stored

# which would later be copied to final_path[]

def TSPRec(adj, curr_bound, curr_weight,

level, curr_path, visited):

global final_res

# base case is when we have reached level N


# which means we have covered all the nodes once

if level == N:

# check if there is an edge from

# last vertex in path back to the first vertex

if adj[curr_path[level - 1]][curr_path[0]] != 0:

# curr_res has the total weight

# of the solution we got

curr_res = curr_weight + adj[curr_path[level - 1]]\

[curr_path[0]]

if curr_res < final_res:

copyToFinal(curr_path)

final_res = curr_res

return

# for any other level iterate for all vertices

# to build the search space tree recursively

for i in range(N):

# Consider next vertex if it is not same

# (diagonal entry in adjacency matrix and

# not visited already)

if (adj[curr_path[level-1]][i] != 0 and

visited[i] == False):

temp = curr_bound

curr_weight += adj[curr_path[level - 1]][i]


# different computation of curr_bound

# for level 2 from the other levels

if level == 1:

curr_bound -= ((firstMin(adj, curr_path[level - 1]) +

firstMin(adj, i)) / 2)

else:

curr_bound -= ((secondMin(adj, curr_path[level - 1]) +

firstMin(adj, i)) / 2)

# curr_bound + curr_weight is the actual lower bound

# for the node that we have arrived on.

# If current lower bound < final_res,

# we need to explore the node further

if curr_bound + curr_weight < final_res:

curr_path[level] = i

visited[i] = True

# call TSPRec for the next level

TSPRec(adj, curr_bound, curr_weight,

level + 1, curr_path, visited)

# Else we have to prune the node by resetting

# all changes to curr_weight and curr_bound

curr_weight -= adj[curr_path[level - 1]][i]

curr_bound = temp
# Also reset the visited array

visited = [False] * len(visited)

for j in range(level):

if curr_path[j] != -1:

visited[curr_path[j]] = True

# This function sets up final_path

def TSP(adj):

# Calculate initial lower bound for the root node

# using the formula 1/2 * (sum of first min +

# second min) for all edges. Also initialize the

# curr_path and visited array

curr_bound = 0

curr_path = [-1] * (N + 1)

visited = [False] * N

# Compute initial bound

for i in range(N):

curr_bound += (firstMin(adj, i) +

secondMin(adj, i))

# Rounding off the lower bound to an integer

curr_bound = math.ceil(curr_bound / 2)

# We start at vertex 1 so the first vertex

# in curr_path[] is 0

visited[0] = True
curr_path[0] = 0

# Call to TSPRec for curr_weight

# equal to 0 and level 1

TSPRec(adj, curr_bound, 0, 1, curr_path, visited)

# Driver code

# Adjacency matrix for the given graph

adj = [[0, 10, 15, 20],

[10, 0, 35, 25],

[15, 35, 0, 30],

[20, 25, 30, 0]]

N=4

# final_path[] stores the final solution

# i.e. the // path of the salesman.

final_path = [None] * (N + 1)

# visited[] keeps track of the already

# visited nodes in a particular path

visited = [False] * N

# Stores the final minimum weight

# of shortest tour.

final_res = maxsize

TSP(adj)

print("Minimum cost :", final_res)

print("Path Taken : ", end = ' ')

for i in range(N + 1):

print(final_path[i], end = ' ')


OUTPUT:

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:

To implement assignment problem using branch and bound technique.

ALGORITHM:

STEP 1: Start with a cost matrix representing the cost of assigning workers to tasks.

STEP 2: Perform Row Reduction

STEP 3: Perform Column Reduction

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 5: Find Smallest Uncovered Element

STEP 6: Subtract this smallest uncovered element from all uncovered rows and add it to all
covered columns.

STEP 7: Repeat Steps 4 to 6

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

# Step 3: Create a mask matrix and cover rows and columns


mask = np.zeros((n, n), dtype=bool)
row_covered = np.zeros(n, dtype=bool)
col_covered = np.zeros(n, dtype=bool)

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

# Step 4: Find the minimum number of lines to cover all zeros


min_lines = min(n, n)

while min_lines < n:


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) 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)

while min_lines < n:


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) 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 7: Create assignments and return the result


assignments = np.zeros((n, 2), dtype=int)

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.

You might also like