LP2 Prac
LP2 Prac
while queue:
vertex = queue.popleft()
print(vertex, end=" ")
graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B', 'F'],
'F': ['C', 'E']
}
visited = set()
print("\nDepth First Search Traversal:")
dfs(graph, 'A', visited)
while stack:
vertex = stack.pop() # Pop the top node
if vertex not in visited:
print(vertex, end=" ")
visited.add(vertex)
# Push adjacent vertices (unvisited) onto the stack
# Reverse to maintain order (optional)
for neighbor in reversed(graph[vertex]):
if neighbor not in visited:
stack.append(neighbor)
Implement Depth First Search (DFS) and Breadth First Search (BFS) algorithms using an undirected
graph, developing a recursive algorithm for DFS to search all vertices.
Theory:
Depth First Search (DFS):
DFS is a graph traversal algorithm that explores as far along each branch as possible before
backtracking.
Main data structure: Stack (explicit or via recursion).
Types of edges:
Discovery Edge: Leads to an unvisited node.
Block Edge: Leads to an already visited node.
Pseudocode:
DFS(G, u):
u.visited = true
for each v in G.Adj[u]:
if v.visited == false:
DFS(G, v)
init():
For each u in G:
u.visited = false
For each u in G:
if u.visited == false:
DFS(G, u)
Complexity: Time: O(V + E) Space: O(V)
Algorithm Steps:
Mark the starting vertex as visited and enqueue it.
Dequeue a vertex, visit all its unvisited adjacent vertices and enqueue them.
Repeat until the queue is empty.
Pseudocode:
BFS(G, v):
create a queue Q
mark v as visited
enqueue v into Q
while Q is not empty:
u = dequeue Q
for each neighbor w of u:
if w is not visited:
mark w as visited
enqueue w
Complexity: Time: O(V + E) Space: O(V)
In DFS program
In BFS program:
Every recursive call in DFS pushes the next node onto the call stack, and pops it
when returning.
✅ Summary:
Recursive DFS = uses internal call stack automatically (no manual stack needed).
BFS must process nodes level by level, i.e., first-in, first-out (FIFO) order.
Recursion doesn't work well for BFS because recursion is depth-first, not breadth-
first.
✅ Summary:
Here is the undirected graph you asked for (same for both DFS and BFS):
Visual Representation:
mathematica
CopyEdit
A
/ \
B C
/ \ \
D E -- F
A → B → D → E → F → C
Iterative BFS using an explicit queue (here a Python list with pop(0))
def bfs_iterative(graph):
visited = set()
order = []
queue = []
if __name__ == "__main__":
# Define an undirected graph as an adjacency list
graph = {
0: [1, 2],
1: [0, 2],
2: [0, 1, 3],
3: [2, 4],
4: [3],
5: [6], # disconnected component
6: [5]
}
Theory:
A* is a best-first search algorithm.
It combines features of Uniform Cost Search (UCS) and Greedy Best First Search.
It uses:
Basic Concept:
Uses heuristic estimation to speed up the search.
Working of A*:
Start from the initial node.
Algorithm Steps:
Place start node in OPEN list.
Else:
✨ ADVANTAGES:
Finds optimal solution (if heuristic is admissible).
⚡ DISADVANTAGES:
High memory usage (keeps all nodes in memory).
import heapq
closed_set = set()
while open_list:
f, g, current_node, path = heapq.heappop(open_list)
if current_node == goal:
return path, g # path and total cost
closed_set.add(current_node)
for neighbor, cost in graph[current_node]:
if neighbor in closed_set:
continue
g_new = g + cost
f_new = g_new + heuristic[neighbor]
heapq.heappush(open_list, (f_new, g_new, neighbor, path +
[neighbor]))
# Example Graph:
# Each node maps to a list of (neighbor, cost)
graph = {
'A': [('B', 1), ('C', 5)],
'B': [('D', 7)],
'C': [('D', 10)],
'D': []
}
# Run A* Search
start_node = 'A'
goal_node = 'D'
path, cost = a_star_search(graph, start_node, goal_node, heuristic)
print("Path:", path)
print("Total Cost:", cost)
OUTPUT:
Path: ['A', 'B', 'D']
Total Cost: 8
✅ It finds the path A -> B -> D with total cost 8, which matches your
example from the experiment theory!
Final Conclusion:
A* search is a powerful, complete, and optimal algorithm when the
heuristic is accurate.
You said:
solve this
ChatGPT said:
Here’s the A* search “by hand” on your graph (start = A, goal = D) using
mathematica
Copy
Edit
h(A)=6, h(B)=4, h(C)=2, h(D)=0
1. Initialization
OPEN = { A } with
g(A)=0
f(A)=g(A)+h(A)=0+6=6
CLOSED = ∅
2. Iteration 1
Select from OPEN the node with smallest f → A (f=6).
Generate successors of A:
3. Iteration 2
Select smallest f in OPEN → B (f=5).
Generate successors of B:
4. Iteration 3
Select smallest f in OPEN → C (f=7).
Generate successors of C:
5. Iteration 4
Select D from OPEN (f=8).
Result
Path found: A → B → D
Total cost: 8
ChatGPT said:
In this toy example the heuristic values
Compute the actual shortest-path costs from each node to D (by inspection of the graph):
From D to itself is 0
Pick any heuristic h(n) that never exceeds that true cost:
We set
h(B)=4 (≤ 7)
h(C)=2 (≤ 10)
h(A)=6 (≤ 8)
Greedy property: Always make the choice that looks best at the moment.
o
Why Union-Find?:
To check efficiently if two vertices are already connected (i.e., prevent cycle).
Is it greedy?:
Yes — always picks the lowest weight edge available.
Edge-based vs Vertex-based:
Kruskal’s is edge-based; Prim’s is vertex-based.
import heapq
while min_heap:
weight, u, parent = heapq.heappop(min_heap)
if visited[u]:
continue
visited[u] = True
if parent != -1:
mst_edges.append((parent, u, weight))
mst_weight += weight
for v, w in adj_list[u]:
if not visited[v]:
heapq.heappush(min_heap, (w, v, u))
n_vertices = 5
class DisjointSet:
def __init__(self, n):
self.parent = list(range(n))
# Graph edges
edges = [
(1, 2, 10), # B-C
(1, 3, 4), # B-D
(2, 0, 3), # C-A
(2, 3, 2), # C-D
(2, 4, 6), # C-E
(3, 4, 1) # D-E
]
n_vertices = 5
N QUEENS
N-Queens Problem Overview:
Approach Used:
Backtracking + Branch and Bound
Backtracking:
➔ Try placing queens one by one. If a conflict is found later,
remove the previously placed queen (backtrack) and try a different
position.
Step-by-Step Working:
Start from the first column.
For each row in the column:
Check if it's safe (no queen in that row, or diagonals).
If safe, place a queen and mark the row and diagonals.
Recursively place the next queen (next column).
If placing a queen leads to no solution, backtrack:
Remove the queen, unmark the row and diagonals.
Continue until all queens are placed successfully or all possibilities
are exhausted.
Q6. Why do we use lookup tables (arrays) for rows and diagonals?
Ans:
To quickly check if a position is safe without scanning the entire
board, reducing time complexity.
Summary Flowchart:
Start ➔ Try placing Queen in column 0 ➔ Check rows 0 to N-1 ➔
If safe ➔ Place ➔ Move to next column ➔ Repeat ➔
If stuck ➔ Backtrack ➔ Try next row ➔ Until all columns filled
Q8. How does the solution avoid placing two queens in the same
column?
Ans:
The queens are placed one per column recursively, so no two queens
are ever in the same column.
Constraints → Rules that restrict the values the variables can take.
Example:
Variables: X, Y, Z
Domain: {1, 2, 3}
Constraints: X ≠ Y, Y ≠ Z, X ≠ Z
2. ⚡ Backtracking
Definition:
Backtracking is a technique to build a solution step-by-step and
undo choices (backtrack) when a choice leads to failure.
How it works:
Start with an empty solution.
Example:
Place a queen in the first column.
How it works:
Explore only promising branches.
Example:
If placing a queen makes no more safe places, stop immediately
instead of continuing.
4. N-Queens Problem
Definition:
The N-Queens problem asks you to place N queens on an N×N
chessboard so that:
def take_input():
#Accepts the size of the chess board
while True:
try:
n = int(input('Input size of chessboard? n = '))
if n <= 3:
print("Enter a value greater than or equal to 4")
continue
return n
except ValueError:
print("Invalid value entered. Enter again")
def get_board(n):
#Returns an n by n board
board = ["x"]*n
for i in range(n):
board[i] = ["x"]*n
return board
def print_solution(solutions, n):
#Prints one of the solutions randomly
x = random.randint(0,len(solutions)-1) #0 and len(solutions)-1 are
inclusive
for row in solutions[x]:
print(" ".join(row))
for i in range(n):
if is_safe(board, i, col, n):
board[i][col] = "Q"
if col == n-1:
add_solution(board)
board[i][col] = "x"
return
solve(board, col+1, n) #recursive call
#backtrack
board[i][col] = "x"
i, j = row, col
while i >= 0 and j >= 0:
if board[i][j] == "Q":
return False
i=i-1
j=j-1
x, y = row,col
while x < n and y >= 0:
if board[x][y] == "Q":
return False
x=x+1
y=y-1
return True
def add_solution(board):
#Saves the board state to the global variable: solutions
global solutions
saved_board = copy.deepcopy(board)
solutions.append(saved_board)
print()
print()
print("Total number of solutions=", len(solutions))
Input size of chessboard? n = 8
One of the solutions is:
xx xQx xx x
xx xx xQx x
xx xx xx x Q
xx Qx x xx x
Qx xx x xx x
xx xx xx Qx
xx xx Qxx x
xQxx x xx x
Total number of solutions= 92
N-Queens Problem:
Backtracking Approach:
Smarter backtracking.
Prune dead-end paths early (don’t explore further).
o
o
o
o
Diagonal Calculation:
return True
def solve_nqueens_backtrack(board, row, n):
if row == n:
print_board(board, n)
return True # Change to False if you want **all** solutions
return False
def n_queens_backtracking(n):
board = [[0 for _ in range(n)] for _ in range(n)]
solve_nqueens_backtrack(board, 0, n)
# Example
n_queens_backtracking(8)
# Backtrack
board[row][col] = 0
left_row[col] = lower_diag[row + col] = upper_diag[n - 1
+ col - row] = 0
return False
def n_queens_branch_and_bound(n):
board = [[0 for _ in range(n)] for _ in range(n)]
left_row = [0] * n
lower_diag = [0] * (2 * n - 1)
upper_diag = [0] * (2 * n - 1)
Final Conclusion
You have learned how to solve n-Queens using both Backtracking and Branch
and Bound.
Both approaches correctly place queens such that no two attack each other.
By providing a natural language interface, chatbots eliminate the need for users to learn new systems
and interfaces. AI-powered chatbots are evolving to deliver highly personalized experiences, making
them a critical part of modern business-customer interactions.
Why Chatbots?
Improve customer service by providing instant responses.
Preferred by users for being faster and more convenient compared to human support.
Offer 24/7 availability and handle simultaneous conversations with thousands of users.
The exponential growth in chatbot adoption (from 30,000 in 2016 to over 100,000 today)
highlights their importance in modern business strategies. By 2020, nearly 80% of businesses had
planned to implement chatbots.
Benefits of Chatbots:
Available 24×7:
No need for customers to wait. Chatbots respond immediately, improving customer satisfaction.
Cost Savings:
Reduces the need for large customer support teams by automating basic queries.
Sales Generation:
Chatbots can recommend products, offer discounts, and enable instant ordering over chat.
Healthcare:
Answer health-related queries.
Offer instant support and health tips without waiting for a doctor.
E-commerce:
Personalized shopping experiences.
Fashion Industry:
Offer personal styling recommendations.
Conclusion:
Chatbots are revolutionizing the way businesses interact with customers by offering fast, intelligent,
and personalized experiences. As industries increasingly adopt chatbots, businesses must leverage
them to enhance customer satisfaction, reduce operational costs, and drive more revenue.
def remind_name():
print('Please, remind me your name.')
name = input()
print("What a great name you have, {0}!".format(name))
def guess_age():
print('Let me guess your age.')
print('Enter remainders of dividing your age by 3, 5 and
7.')
rem3 = int(input())
rem5 = int(input())
rem7 = int(input())
age = (rem3 * 70 + rem5 * 21 + rem7 * 15) % 105
def count():
print('Now I will prove to you that I can count to any
number you want.')
num = int(input())
counter = 0
while counter <= num:
print("{0} !".format(counter))
counter += 1
def test():
print("Let's test your programming knowledge.")
print("Why do we use methods?")
print("1. To repeat a statement multiple times.")
print("2. To decompose a program into several small
subroutines.")
print("3. To determine the execution time of a program.")
print("4. To interrupt the execution of a program.")
answer = 2
guess = int(input())
while guess != answer:
print("Please, try again.")
guess = int(input())
def end():
print('Congratulations, have a nice day!')
print('.................................')
print('.................................')
print('.................................')
input()
def welcome():
print("Hello! I'm Chatty Bot.")
print("I was created to make your day a little
brighter.\n")
def get_name():
print("What's your name, friend?")
name = input("> ")
print(f"Nice to meet you, {name}!\n")
def guess_age():
print("Let me guess your age.")
print("Enter the remainders of your age when divided by
3, 5 and 7.")
rem3 = int(input("Remainder when divided by 3: "))
rem5 = int(input("Remainder when divided by 5: "))
rem7 = int(input("Remainder when divided by 7: "))
age = (rem3 * 70 + rem5 * 21 + rem7 * 15) % 105
print(f"I’m quite sure you are {age} years old!\n")
def count_numbers():
print("Now I can count for you. Give me any number,
please.")
num = int(input("> "))
for i in range(num + 1):
print(f"{i}!")
print()
def programming_quiz():
print("Let's test your programming knowledge.")
print("Why do we use functions?")
options = [
"1. To repeat a statement multiple times.",
"2. To decompose a program into smaller
subroutines.",
"3. To determine the execution time of a program.",
"4. To interrupt the execution of a program."
]
for opt in options:
print(opt)
while True:
choice = int(input("> "))
if choice == 2:
print("Correct! Well done.\n")
break
else:
print("Oops, that's not it. Try again!")
def end_message():
print("Congratulations, you’ve completed all stages of
the chatbot demo!")
print("Have a great day ahead! ")
def main():
welcome()
get_name()
guess_age()
count_numbers()
programming_quiz()
end_message()
if __name__ == "__main__":
main()
AMAZON EC2
Amazon EC2 (Elastic Compute Cloud) is AWS's virtual server service
that provides flexible, scalable, pay-per-use compute power.
Key Pair: Required for securely connecting (SSH for Linux or RDP
for Windows instances).
1. Login to AWS
Go to AWS Management Console → Sign in as Root User.
Download the .pem file and keep it safe (used for connecting).
5. Configure and Launch Instance
Select AMI: Choose an Amazon Machine Image (like Ubuntu 20.04
or Windows Server).
6. Launch
Select your previously created Key Pair.
Click Launch Instance.
Instance will start provisioning.
Conclusion
EC2 instances let you easily deploy, scale, and manage applications
without buying physical servers.
Manage costs by stopping or terminating unused instances.
3. What is an AMI?
Answer:
AMI stands for Amazon Machine Image. It is a template that contains the software configuration
(operating system, application server, and applications) required to launch an EC2 instance.
Terminate: Deletes the instance and its attached storage (unless EBS is configured to persist).
Key Features:
Use cases:
SMEs, Enterprises needing to scale web apps without worrying about infrastructure.
Advantages:
Top-notch security (Google-grade).
✅ Detailed Explanation:
GAE abstracts all server management.
You upload your code → Google automatically handles scaling, load balancing, security, monitoring.
Supports dynamic web apps and APIs.
Ideal for apps needing global reach and scalability.
Summary:
✅ Example:
If your app has 10 users today and 10 million users tomorrow, GAE can handle it without needing
you to add servers manually.
Step-by-Step Execution
Step 1: Login
Open Salesforce Developer → Login to your account.
1. What is Salesforce?
Answer:
Salesforce is a cloud-based CRM (Customer Relationship Management) platform that helps businesses
manage customer data, sales, marketing, support, and operations through applications hosted in the
cloud.
9. What are the key methods used for sending an Email in Apex?
Answer:
setToAddresses(): Sets the recipient email.
setSubject(): Sets the subject line.
setPlainTextBody(): Sets the body of the email.
sendEmail(): Actually sends the email.
Salesforce Architecture
Multi-tenant: Many customers share the same server hardware, but logically isolated.
Metadata-driven: You can customize apps without needing to touch the actual database or servers.
Cloud-native: No hardware/software installations required.
public class EM {
public static void sendMail(String address, String subject, String body)
{
Messaging.SingleEmailMessage mail = new
Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {address};
mail.setToAddresses(toAddresses);
mail.setSubject(subject);
mail.setPlainTextBody(body);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Salesforce = Cloud platform for building custom business apps without heavy coding.
Custom Object = Like creating a new table in a database (example: "Student" = Stud).
Fields and Relationships = Like columns in a table (example: "Class", "Name", "Age").
Tabs = UI elements that make the custom objects visible and accessible.
1. Login to Salesforce
Go to Salesforce login.
Example:
Label: Stud
Plural Label: Studs
Example:
Label: Read_Books
Plural Label: Read_Books
Save.
Create a field:
Choose:
Object: Stud
Fill Details:
Click Next.
Final Recap: