0% found this document useful (0 votes)
18 views

DAA RECORD 6 TO 9

Uploaded by

teashobana
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)
18 views

DAA RECORD 6 TO 9

Uploaded by

teashobana
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/ 28

6(A)-GREEDY TECHNIQUE

DIJKSTRA’S ALGORITHM

PROGRAM:

import heapq

# Function to implement Dijkstra's algorithm using a greedy approach


def dijkstra(graph, start):
# Number of nodes in the graph
num_nodes = len(graph)

# Initialize distances from start to all nodes as infinity


distances = {node: float('inf') for node in range(num_nodes)}
distances[start] = 0 # Distance to start node is 0

# Priority queue to keep track of the next node to visit


pq = [(0, start)] # (distance, node)

while pq:
# Get the node with the smallest distance
current_distance, current_node = heapq.heappop(pq)

# If the current distance is greater than the recorded distance, skip processing
if current_distance > distances[current_node]:
continue

# Explore each neighbor of the current node


for neighbor, weight in graph[current_node]:
distance = current_distance + weight

# If a shorter path to the neighbor is found, update the distance and add to queue
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))

return distances

# Function to take user input and run the algorithm


def main():
# Get number of nodes and edges from the user
num_nodes = int(input("Enter number of nodes: "))
num_edges = int(input("Enter number of edges: "))

# Initialize the graph as an adjacency list


graph = {i: [] for i in range(num_nodes)}

# Get the edges from the user (format: node1 node2 weight)
for _ in range(num_edges):
u, v, w = map(int, input("Enter edge (u, v, weight): ").split())
graph[u].append((v, w))
graph[v].append((u, w)) # Assuming an undirected graph

# Get the source node for Dijkstra's algorithm


start_node = int(input("Enter the start node: "))

# Run Dijkstra's algorithm


distances = dijkstra(graph, start_node)

# Output the shortest distances


print("\nShortest distances from node", start_node)
for node, distance in distances.items():
print(f"Node {node}: {distance}")

if __name__ == "__main__":
main()
OUTPUT:

Enter number of nodes: 5


Enter number of edges: 6
Enter edge (u, v, weight): 0 1 10
Enter edge (u, v, weight): 0 2 5
Enter edge (u, v, weight): 1 2 2
Enter edge (u, v, weight): 1 3 1
Enter edge (u, v, weight): 2 3 9
Enter edge (u, v, weight): 3 4 4
Enter the start node: 0
Shortest distances from node 0
Node 0: 0
Node 1: 7
Node 2: 5
Node 3: 8
Node 4: 12
6(B)-GREEDY TECHNIQUE
HUFFMAN TREES AND CODES

PROGRAM:

import heapq

# Helper class for Huffman Tree Node


class Node:
def __init__(self, char, freq):
self.char = char
self.freq = freq
self.left = None
self.right = None

# For heapq to compare nodes based on frequency


def __lt__(self, other):
return self.freq < other.freq

# Function to build the Huffman Tree


def build_huffman_tree(freq_table):
# Create a priority queue (min-heap)
heap = [Node(char, freq) for char, freq in freq_table.items()]
heapq.heapify(heap)

# Build the Huffman Tree


while len(heap) > 1:
# Pop the two nodes with the lowest frequency
left = heapq.heappop(heap)
right = heapq.heappop(heap)

# Create a new internal node with the sum of frequencies


merged_node = Node(None, left.freq + right.freq)
merged_node.left = left
merged_node.right = right

# Push the internal node back into the priority queue


heapq.heappush(heap, merged_node)

# The root of the tree is the only remaining node in the heap
return heap[0]

# Function to generate Huffman codes from the tree


def generate_huffman_codes(node, current_code, codes):
if node is None:
return

# If we reached a leaf node, assign the Huffman code


if node.char is not None:
codes[node.char] = current_code

# Recursively generate codes for left and right subtrees


generate_huffman_codes(node.left, current_code + '0', codes)
generate_huffman_codes(node.right, current_code + '1', codes)

# Function to encode the text using Huffman codes


def encode_text(text, huffman_codes):
return ''.join(huffman_codes[char] for char in text)

# Function to decode the encoded text using the Huffman tree


def decode_text(encoded_text, root):
decoded_text = []
current_node = root
for bit in encoded_text:
# Traverse the tree based on the bit (0 = left, 1 = right)
current_node = current_node.left if bit == '0' else current_node.right

# If we reach a leaf node, add the character to decoded text


if current_node.char is not None:
decoded_text.append(current_node.char)
current_node = root # Restart from root after decoding a character

return ''.join(decoded_text)

# Main function to handle user input and perform the operations


def main():
# Get the number of characters in the frequency table
num_chars = int(input("Enter the number of unique characters: "))

# Input the character and frequency pairs


freq_table = {}
print("Enter character and frequency pairs (e.g., A 5, B 9, C 12):")
for _ in range(num_chars):
char, freq = input().split()
freq_table[char] = int(freq)

# Build Huffman Tree using the frequency table


root = build_huffman_tree(freq_table)

# Generate Huffman codes from the tree


huffman_codes = {}
generate_huffman_codes(root, '', huffman_codes)

# Display the generated Huffman codes


print("\nHuffman Codes:")
for char, code in huffman_codes.items():
print(f"Character: '{char}' | Code: {code}")

# Take the text input for encoding


text = input("\nEnter the text to encode: ")

# Encode the text using Huffman codes


encoded_text = encode_text(text, huffman_codes)
print("\nEncoded text:", encoded_text)

# Decode the encoded text


decoded_text = decode_text(encoded_text, root)
print("\nDecoded text:", decoded_text)

if __name__ == "__main__":
main()
OUTPUT:

Enter the number of unique characters: 5


Enter character and frequency pairs (e.g., A 5, B 9, C 12):
A5
B9
C 12
D 13
E 16

Enter the text to encode: ABCD


Huffman Codes:
Character: 'A' | Code: 000
Character: 'B' | Code: 01
Character: 'C' | Code: 10
Character: 'D' | Code: 11
Character: 'E' | Code: 111

Encoded text: 0000101011

Decoded text: ABCD


7-ITERATIVE IMPROVEMENT
SIMPLEX METHOD

PROGRAM:

import numpy as np

def simplex(c, A, b):


num_variables = len(c)
num_constraints = len(b)

tableau = np.hstack([A, np.eye(num_constraints), b.reshape(-1, 1)])


objective_row = np.hstack([c, np.zeros(num_constraints + 1)])
tableau = np.vstack([tableau, objective_row])

while True:
if np.all(tableau[-1, :-1] >= 0):
return tableau[:-1, -1], tableau[-1, -1]

pivot_col = np.argmin(tableau[-1, :-1])

ratios = tableau[:-1, -1] / tableau[:-1, pivot_col]


ratios[ratios <= 0] = np.inf
pivot_row = np.argmin(ratios)

pivot_value = tableau[pivot_row, pivot_col]


tableau[pivot_row] /= pivot_value

for i in range(len(tableau)):
if i != pivot_row:
tableau[i] -= tableau[i, pivot_col] * tableau[pivot_row]

def main():
num_variables = int(input("Enter the number of variables: "))
num_constraints = int(input("Enter the number of constraints: "))

c = np.array(list(map(float, input(f"Enter the coefficients of the objective function (c):


").split())))

A = []
for _ in range(num_constraints):
A.append(list(map(float, input(f"Enter the coefficients for constraint {_ + 1}: ").split())))

b = np.array(list(map(float, input("Enter the right-hand side values (b): ").split())))

optimal_solution, optimal_value = simplex(c, np.array(A), b)

print("\nOptimal Solution (Variable Values):")


for i, value in enumerate(optimal_solution):
print(f"x{i + 1} = {value}")

print(f"\nOptimal Value of the Objective Function: {optimal_value}")

if __name__ == "__main__":
main()
OUTPUT:

Enter the number of variables: 2


Enter the number of constraints: 2
Enter the coefficients of the objective function (c): 3 2
Enter the coefficients for constraint 1: 1 1
Enter the coefficients for constraint 2: 2 1
Enter the right-hand side values (b): 4 5
Optimal Solution (Variable Values):
x1 = 1.0
x2 = 3.0

Optimal Value of the Objective Function: 9.0


8(A)-BACKTRACKING N-QUEEN PROBLEM

PROGRAM:

def is_safe(board, row, col, n):


for i in range(row):
if board[i] == col or \
board[i] - i == col - row or \
board[i] + i == col + row:
return False
return True

def solve_nqueens(board, row, n):


if row == n:
print_solution(board, n)
return True

res = False
for col in range(n):
if is_safe(board, row, col, n):
board[row] = col
res = solve_nqueens(board, row + 1, n) or res
board[row] = -1 # Backtrack

return res

def print_solution(board, n):


for i in range(n):
row = ['.'] * n
row[board[i]] = 'Q'
print(' '.join(row))
print()

def main():
n = int(input("Enter the number of queens (N): "))
board = [-1] * n
if not solve_nqueens(board, 0, n):
print("Solution does not exist")

if __name__ == "__main__":
main()
OUTPUT:

Enter the number of queens (N): 4

.Q..
...Q
Q...
..Q.
8(B)-BACKTRACKING-SUBSET SUM PROBLEM

PROGRAM:

def subset_sum(arr, target, current_sum=0, index=0, current_subset=[]):


if current_sum == target:
print("Subset found:", current_subset)
return True
if current_sum > target or index >= len(arr):
return False

# Include the current element in the subset


current_subset.append(arr[index])
if subset_sum(arr, target, current_sum + arr[index], index + 1, current_subset):
return True

# Backtrack and exclude the current element from the subset


current_subset.pop()
if subset_sum(arr, target, current_sum, index + 1, current_subset):
return True

return False

def main():
arr = list(map(int, input("Enter the array of numbers: ").split()))
target = int(input("Enter the target sum: "))
if not subset_sum(arr, target):
print("No subset found with the given sum.")

if __name__ == "__main__":
main()
OUTPUT:

Enter the array of numbers: 3 34 4 12 5 2


Enter the target sum: 9
Subset found: [4, 5]
9(A)-BRANCH AND BOUND-ASSIGNEMENT PROBLEM

PROGRAM:

import numpy as np
import heapq

class Node:
def __init__(self, level, cost_matrix, assigned, cost, bound):
self.level = level
self.cost_matrix = cost_matrix
self.assigned = assigned
self.cost = cost
self.bound = bound

def __lt__(self, other):


return self.bound < other.bound

def calculate_lower_bound(cost_matrix, assigned, n):


# Calculate the lower bound based on row and column reductions
# First reduce rows
row_reduced = np.copy(cost_matrix)
row_min = np.min(row_reduced, axis=1)
row_reduced -= row_min[:, np.newaxis]

# Then reduce columns


col_reduced = np.copy(row_reduced)
col_min = np.min(col_reduced, axis=0)
col_reduced -= col_min

# The lower bound is the sum of the row and column reductions
row_reduction_sum = np.sum(row_min)
col_reduction_sum = np.sum(col_min)

return row_reduction_sum + col_reduction_sum

def branch_and_bound(cost_matrix, n):


# Initialize the best solution as a large number
best_cost = float('inf')
best_assignment = None

# Priority queue to explore the state space


queue = []

# Initial Node (level -1, no assignments, no cost, and initial bound)


assigned = [-1] * n
initial_bound = calculate_lower_bound(cost_matrix, assigned, n)
root = Node(-1, cost_matrix, assigned, 0, initial_bound)

heapq.heappush(queue, root)

while queue:
node = heapq.heappop(queue)

# If the lower bound is greater than the best solution found so far, prune the branch
if node.bound >= best_cost:
continue
# If we have assigned all tasks (level == n-1), check if we have a better solution
if node.level == n - 1:
if node.cost < best_cost:
best_cost = node.cost
best_assignment = node.assigned.copy()
continue

# Generate the next level nodes (assign the next task to a worker)
level = node.level + 1
for j in range(n):
if node.assigned[j] == -1: # If worker j is not yet assigned
new_assigned = node.assigned.copy()
new_assigned[j] = level

# Create a new cost matrix by marking the current row as assigned


new_cost_matrix = np.copy(node.cost_matrix)
new_cost_matrix[level, :] = float('inf') # Exclude the current row

# Calculate the new bound


new_cost = node.cost + cost_matrix[level][j]
new_bound = calculate_lower_bound(new_cost_matrix, new_assigned, n)

# If the bound is promising, push it into the priority queue


if new_bound < best_cost:
heapq.heappush(queue, Node(level, new_cost_matrix, new_assigned, new_cost,
new_bound))

return best_cost, best_assignment

def main():
# Read the input for the Assignment Problem
n = int(input("Enter the number of workers/tasks (n): "))
print("Enter the cost matrix:")
cost_matrix = []
for _ in range(n):
OUTPUT:

Enter the number of workers/tasks (n): 4


Enter the cost matrix:
10 15 20 25
20 25 30 35
30 35 40 45
40 45 50 55
Optimal Assignment (Task -> Worker): [0, 1, 2, 3]
Minimum Cost: 80
9(B)-BRANCH AND BOUND-TRAVELLING SALES MAN

PROGRAM:

import numpy as np
import heapq

class Node:
def __init__(self, level, cost, path, bound):
self.level = level # Current level (number of cities visited)
self.cost = cost # Total cost of the path so far
self.path = path # List of cities visited so far
self.bound = bound # Lower bound for this node

def __lt__(self, other):


return self.bound < other.bound # Priority queue sorted by bound

def calculate_lower_bound(cost_matrix, path, n):


"""
Calculate the lower bound for a node.
Uses matrix reduction method (similar to the MST bound).
"""
# Calculate the row reduction
row_reduced = np.copy(cost_matrix)
for i in range(n):
row_min = np.min(row_reduced[i][np.where(row_reduced[i] != float('inf'))]) # min in
the row
if row_min != float('inf'):
row_reduced[i] -= row_min
# Calculate the column reduction
col_reduced = np.copy(row_reduced)
for j in range(n):
col_min = np.min(col_reduced[np.where(col_reduced[:, j] != float('inf')), j]) # min in
the column
if col_min != float('inf'):
col_reduced[:, j] -= col_min

# Add row and column reductions to calculate the lower bound


row_reduction_sum = np.sum(np.min(row_reduced, axis=1))
col_reduction_sum = np.sum(np.min(col_reduced, axis=0))

return row_reduction_sum + col_reduction_sum

def branch_and_bound_tsp(cost_matrix, n):


# Priority queue to explore the search space
min_heap = []

# Initial state (starting from city 0)


path = [0]
cost = 0
initial_bound = calculate_lower_bound(cost_matrix, path, n)

root = Node(level=0, cost=cost, path=path, bound=initial_bound)


heapq.heappush(min_heap, root)

best_cost = float('inf')
best_path = None

while min_heap:
# Get the node with the smallest bound (best possible solution so far)
node = heapq.heappop(min_heap)

# If the bound is greater than the best cost, prune this branch
if node.bound >= best_cost:
continue

# If all cities are visited, check if this is the best solution


if node.level == n - 1:
last_city = node.path[-1]
# Complete the tour by returning to the starting city
total_cost = node.cost + cost_matrix[last_city][0]
if total_cost < best_cost:
best_cost = total_cost
best_path = node.path + [0] # Return to the start city
continue

# Generate the child nodes (add a new city to the path)


for city in range(n):
if city not in node.path:
new_path = node.path + [city]
new_cost = node.cost + cost_matrix[node.path[-1]][city]
new_bound = calculate_lower_bound(cost_matrix, new_path, n)

# If the new bound is promising, push it into the queue


if new_bound < best_cost:
heapq.heappush(min_heap, Node(level=node.level + 1, cost=new_cost,
path=new_path, bound=new_bound))

return best_cost, best_path


def main():
# Input the number of cities
n = int(input("Enter the number of cities: "))
print("Enter the distance matrix:")
cost_matrix = []
for i in range(n):
row = list(map(int, input().split()))
cost_matrix.append(row)

# Solve the TSP using Branch and Bound


min_cost, best_path = branch_and_bound_tsp(np.array(cost_matrix), n)

print(f"\nOptimal Path: {best_path}")


print(f"Minimum Cost: {min_cost}")

if __name__ == "__main__":
main()
OUTPUT:

Enter the number of cities: 4


Enter the distance matrix:
0 10 15 20
10 0 35 25
15 35 0 30
20 25 30 0
Optimal Path: [0, 1, 3, 2, 0]
Minimum Cost: 80

You might also like