0% found this document useful (0 votes)
3 views55 pages

LP2 Prac

The document provides implementations and explanations of graph traversal algorithms including Depth First Search (DFS) and Breadth First Search (BFS), detailing their recursive and iterative forms. It also covers the A* algorithm for pathfinding, outlining its advantages and disadvantages, and includes a summary of Prim's and Kruskal's algorithms for Minimum Spanning Trees (MST). Key points include the use of stacks and queues in DFS and BFS, respectively, and the importance of heuristic functions in the A* algorithm.

Uploaded by

aditi
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)
3 views55 pages

LP2 Prac

The document provides implementations and explanations of graph traversal algorithms including Depth First Search (DFS) and Breadth First Search (BFS), detailing their recursive and iterative forms. It also covers the A* algorithm for pathfinding, outlining its advantages and disadvantages, and includes a summary of Prim's and Kruskal's algorithms for Minimum Spanning Trees (MST). Key points include the use of stacks and queues in DFS and BFS, respectively, and the importance of heuristic functions in the A* algorithm.

Uploaded by

aditi
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/ 55

# Python program for DFS traversal (recursive)

def dfs(graph, vertex, visited):


print(vertex, end=" ")
visited.add(vertex)

for neighbor in graph[vertex]:


if neighbor not in visited:
dfs(graph, neighbor, visited)

# Python program for BFS traversal (using queue)

from collections import deque

def bfs(graph, start):


visited = set()
queue = deque([start])
visited.add(start)

while queue:
vertex = queue.popleft()
print(vertex, end=" ")

for neighbor in graph[vertex]:


if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)

# Example Undirected Graph

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)

print("\nBreadth First Search Traversal:")


bfs(graph, 'A')

# Python program for Iterative DFS traversal (using explicit stack)

def iterative_dfs(graph, start):


visited = set() # To track visited vertices
stack = [start] # Initialize stack with the starting node

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)

# Example Undirected Graph (Same as before)


graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B', 'F'],
'F': ['C', 'E']
}

print("Iterative Depth First Search Traversal:")


iterative_dfs(graph, 'A')

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.

Recursive Nature: DFS naturally fits recursion.


Algorithm Steps:

Mark the starting vertex as visited.


Visit all unvisited adjacent vertices recursively.
If no unvisited adjacent vertices remain, backtrack.

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)

Breadth First Search (BFS):


BFS is a graph traversal algorithm that explores all neighbors at the current depth before moving on
to the next depth level.
Main data structure: Queue.

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)

Important Points Summary:


 DFS explores depth (deep paths first), uses recursion or stack.
 BFS explores breadth (level-by-level), uses queue.
 Both traverse all reachable nodes but in different orders.
 Time Complexity: O(V + E) for both.
 Space Complexity: O(V) for both.
 DFS is naturally recursive, BFS is naturally iterative.

What are we using in the program?

In DFS program

We are using a recursive function

Visited Nodes are stored in a Python set (visited = set()).

In BFS program:

We are using an explicit queue (collections.deque in Python).

Visited Nodes are again stored in a Python set.

Why are we not using an explicit Stack for DFS?

Recursion itself uses the function call stack internally.

Every recursive call in DFS pushes the next node onto the call stack, and pops it
when returning.

So we don't need to create a separate stack manually — recursion already manages


it.

If we were to write iterative DFS, then we would use an explicit stack.

✅ Summary:
Recursive DFS = uses internal call stack automatically (no manual stack needed).

Iterative DFS = requires explicit stack.

Why do we explicitly use a Queue for BFS?

BFS must process nodes level by level, i.e., first-in, first-out (FIFO) order.

A queue naturally provides FIFO behavior.

Recursion doesn't work well for BFS because recursion is depth-first, not breadth-
first.

✅ Summary:

BFS always uses a queue — recursion is not suited for BFS.

Graph Example Used in DFS and BFS Traversals

Here is the undirected graph you asked for (same for both DFS and BFS):

Graph (Adjacency List):

Vertex Adjacent Vertices


A B, C
B A, D, E
C A, F
D B
E B, F
F C, E

Visual Representation:

mathematica
CopyEdit
A
/ \
B C
/ \ \
D E -- F

Edges are undirected:


e.g., (A-B), (A-C), (B-D), (B-E), (E-F), (C-F).
Traversal Orders:

DFS Traversal from 'A':

A → B → D → E → F → C

(Go deep from A to B, then D, back to B, then E, then F,


back, then C.)

BFS Traversal from 'A':


A → B → C → D → E → F

(First A, then B and C (A's neighbors), then D and E (B’


s neighbors), and then F.)

Quick Final Notes:


Topic DFS BFS
Stack (internal with
Data Structure Queue (explicit)
recursion)
Behavior Deep first Level by level
Space
O(V) O(V)
Complexity
Time
O(V + E) O(V + E)
Complexity
Maze solving, Topological Shortest path (unweighted
Common Usage
Sort graphs)

Iterative DFS using an explicit stack

Iterative BFS using an explicit queue (here a Python list with pop(0))

# Simple iterative DFS and BFS on an undirected graph


def dfs_iterative(graph):
visited = set()
order = []
stack = []
for start in graph:
if start not in visited:
stack.append(start)
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
order.append(node)
# Push neighbors onto stack
# (optional: reverse for a particular order)
for neighbor in graph[node]:
if neighbor not in visited:
stack.append(neighbor)
return order

def bfs_iterative(graph):
visited = set()
order = []
queue = []

for start in graph:


if start not in visited:
queue.append(start)
visited.add(start)
while queue:
node = queue.pop(0)
order.append(node)
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return order

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]
}

print("DFS order:", dfs_iterative(graph))


print("BFS order:", bfs_iterative(graph))

SUMMARY of Experiment 2: A* Algorithm


Aim:
Implement the A* (A-star) Algorithm for any game/search problem.

Theory:
A* is a best-first search algorithm.

It combines features of Uniform Cost Search (UCS) and Greedy Best First Search.

It uses:

g(n) = cost to reach node n from the start node.

h(n) = heuristic estimated cost from n to goal.

f(n) = g(n) + h(n) → node with smallest f(n) is expanded first.

Basic Concept:
Uses heuristic estimation to speed up the search.

It finds the path with lowest cost by expanding nodes wisely.

Every node keeps track of:

Cost so far (g)

Heuristic cost (h)

Total cost (f)

Working of A*:
Start from the initial node.

Expand the node with smallest f(n).

If it’s the goal, stop.

Else, generate successors and update their g, h, f values.

Maintain two lists:

OPEN list (nodes to be evaluated)

CLOSED list (already evaluated)

Repeat until goal is found or OPEN list is empty.

Algorithm Steps:
Place start node in OPEN list.

While OPEN list is not empty:

Pick node with smallest f(n).

If goal node, success!

Else:

Expand the node → generate successors.

Add successors to OPEN list with updated f(n).

Move expanded node to CLOSED list.

If no path found, return failure.

✨ ADVANTAGES:
Finds optimal solution (if heuristic is admissible).

Very efficient for many problems.

⚡ DISADVANTAGES:
High memory usage (keeps all nodes in memory).

May not be practical for very large search spaces.

SIMPLE, CORRECT PYTHON CODE for A* Algorithm


Let’s implement a basic A* Search on a simple graph!

import heapq

def a_star_search(graph, start, goal, heuristic):


# Priority queue: (f(n), g(n), node, path)
open_list = []
heapq.heappush(open_list, (0 + heuristic[start], 0, start, [start]))

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

return None, float('inf') # no path found

# Example Graph:
# Each node maps to a list of (neighbor, cost)
graph = {
'A': [('B', 1), ('C', 5)],
'B': [('D', 7)],
'C': [('D', 10)],
'D': []
}

# Heuristic values for each node (h(n))


heuristic = {
'A': 6,
'B': 4,
'C': 2,
'D': 0
}

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

Is A the goal? No.

Expand A, move A to CLOSED.

Generate successors of A:

B via A–B (cost 1):


g(B)=g(A)+1=0+1=1
f(B)=1+h(B)=1+4=5

C via A–C (cost 5):


g(C)=0+5=5
f(C)=5+h(C)=5+2=7

Update OPEN = { B(f=5), C(f=7) }

3. Iteration 2
Select smallest f in OPEN → B (f=5).

Is B the goal? No.

Expand B, move B to CLOSED.

Generate successors of B:

D via B–D (cost 7):


g(D)=g(B)+7=1+7=8
f(D)=8+h(D)=8+0=8

Update OPEN = { C(f=7), D(f=8) }

4. Iteration 3
Select smallest f in OPEN → C (f=7).

Is C the goal? No.

Expand C, move C to CLOSED.

Generate successors of C:

D via C–D (cost 10):


g_new(D)=g(C)+10=5+10=15
f_new(D)=15+0=15

Compare: we already have a D in OPEN with f(D)=8; 15 is worse → ignore.

OPEN remains { D(f=8) }

5. Iteration 4
Select D from OPEN (f=8).

Is D the goal? Yes → stop!

Result
Path found: A → B → D

Total cost: 8

heuristic how did u find

ChatGPT said:
In this toy example the heuristic values

h(A)=6, h(B)=4, h(C)=2, h(D)=0


were simply chosen to be admissible estimates of the true remaining cost to reach D. An admissible
heuristic must never over-estimate the actual shortest path cost from a node to the goal.

Here’s how you can “reverse-engineer” them:

Compute the actual shortest-path costs from each node to D (by inspection of the graph):

From B → D: cost is B–D = 7

From C → D: cost is C–D = 10

From A → D: the cheapest route is A–B (1) + B–D (7) = 8

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)

h(D)=0 (exactly the goal)

Because all of these satisfy


h(n) ≤ true_min_cost(n → D),
the heuristic is admissible, and A* is guaranteed to find the optimal path.

Sharp Summary — Prim’s


Algorithm (MST)
Section Key Points
A Minimum Spanning Tree (MST) is a tree that connects
Definition all vertices with the minimum possible total edge
weight.
- Designing water-supply, electrical grids,
Applications telecommunication networks.
- Finding optimized paths in maps.
Algorithm Greedy — Always picks the minimum weight edge at each
Type step without forming a cycle.
1. Start with a random vertex.
Prim's 2. Grow the MST by adding the smallest edge that
Working connects a new vertex.
3. Repeat until all vertices are included.
1. Pick starting vertex.
Algorithm 2. Find minimum weight edge from MST to outside.
Steps 3. Add that edge & vertex.
4. Repeat.
- Adjacency Matrix + Linear Search: O(V²)
Complexity
- Using Min Heap + Adjacency List: O((V + E) log V)
Prim’s algorithm can be improved using heaps (priority
Important
queues) for faster minimum edge extraction.

Important Viva/Exam Points


(must remember)
Prim’s vs Kruskal’s:

Prim's grows a tree one vertex at a time.

Kruskal’s grows a forest (multiple trees) and joins them.

Greedy property: Always make the choice that looks best at the moment.

Graph Representation: Prefer adjacency list + heap for large graphs.

Cycle Prevention: No cycle is formed because we only add new vertices to


MST.

Use Cases: Network design, map routing, electrical wiring.

Sharp Summary — Kruskal's


Algorithm (MST)
Section Key Points
Kruskal’s Algorithm finds the MST by sorting all
Definition edges by weight and picking the smallest ones while
avoiding cycles.
- Same as Prim’s: networks, maps, wiring layouts.
Applications
- Especially useful for sparse graphs.
Algorithm Greedy — Pick smallest weight edges without forming a
Type cycle.
1. Sort all edges by weight (ascending).
2. Pick the smallest edge.
Kruskal's
3. Add it if it does not form a cycle (using Union-
Working
Find DS).
4. Repeat until MST formed.
1. Sort all edges.
Algorithm
2. Use Union-Find to detect cycles.
Steps
3. Add safe edges to MST.
Sorting edges: O(E log E)
Complexity Union-Find operations: almost O(1) (with path
compression).
Cycle detection is key. Uses Disjoint Set (Union-Find)
Important
to prevent cycles.
Important Viva/Exam Points
(must remember)
Prim’s vs Kruskal’s:

Prim’s: grows MST one vertex at a time.

Kruskal’s: grows MST one edge at a time.

o

Why Union-Find?:
To check efficiently if two vertices are already connected (i.e., prevent cycle).


When Kruskal is better?:


For sparse graphs (less edges).

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.

Point Prim’s Kruskal’s


Approach Vertex-based Edge-based
Data Structure Priority Queue Union-Find (Disjoint Set)
Graph Type Suitability Dense Graphs Sparse Graphs
Cycle Prevention Implicit Explicit using Union-Find

import heapq

def prim_mst(adj_list, start=0):


visited = [False] * len(adj_list)
min_heap = [(0, start, -1)] # (weight, current_vertex,
parent)
mst_weight = 0
mst_edges = []

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

return mst_weight, mst_edges

# Build adjacency list


adj_list = {
0: [(2, 3)], # A - C (3)
1: [(2, 10), (3, 4)], # B - C (10), B - D (4)
2: [(1, 10), (0, 3), (3, 2), (4, 6)], # C connected to
B, A, D, E
3: [(1, 4), (2, 2), (4, 1)], # D connected to B, C, E
4: [(2, 6), (3, 1)] # E connected to C, D
}

n_vertices = 5

mst_weight, mst_edges = prim_mst(adj_list, start=1) #


Starting from B (1)

node_map = {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E'}

print("Prim's MST Cost:", mst_weight)


print("Edges in MST:")
for u, v, weight in mst_edges:
print(f"{node_map[u]} - {node_map[v]} (Weight:
{weight})")

Prim's MST Cost: 10 Edges in MST: B - D (Weight: 4) D - E (Weight: 1) D -


C (Weight: 2) C - A (Weight: 3)

class DisjointSet:
def __init__(self, n):
self.parent = list(range(n))

def find(self, u):


if self.parent[u] != u:
self.parent[u] = self.find(self.parent[u])
return self.parent[u]

def union(self, u, v):


u_root = self.find(u)
v_root = self.find(v)
if u_root != v_root:
self.parent[v_root] = u_root
return True
return False

def kruskal_mst(edges, n_vertices):


edges.sort(key=lambda x: x[2]) # Sort by weight
ds = DisjointSet(n_vertices)
mst_weight = 0
mst_edges = []

for u, v, weight in edges:


if ds.union(u, v):
mst_weight += weight
mst_edges.append((u, v, weight))

return mst_weight, mst_edges

# 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

mst_weight, mst_edges = kruskal_mst(edges, n_vertices)

node_map = {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E'}


print("Kruskal's MST Cost:", mst_weight)
print("Edges in MST:")
for u, v, weight in mst_edges:
print(f"{node_map[u]} - {node_map[v]} (Weight:
{weight})")

Kruskal's MST Cost: 10 Edges in MST: D - E (Weight: 1) C - D (Weight: 2) C


- A (Weight: 3) B - D (Weight: 4)
edges.sort(key=lambda x: x[2])
means:
Sort the list based on the 3rd element (index 2) — that is, the weight of the
edge.
The lambda x: x[2] is just a shortcut way of saying:
"For each edge x, use x[2] (weight) as the sorting key."

N QUEENS
N-Queens Problem Overview:

Place N queens on an N×N chessboard so that no two queens


threaten each other.

No two queens can be in the same row, same column, or same


diagonal (left or right).

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.

Branch and Bound:


➔ Before placing a queen, check if placing it leads to a conflict
(using lookup tables).
➔ If conflict → Prune/Eliminates the branch (do not go deeper).

Data Structures Used:


Chessboard matrix: Tracks the current placement of queens (1 =
queen, 0 = empty).

Row Lookup array: Tracks which rows already have queens.

Slash Diagonal Lookup array: Tracks main diagonals (top-left ➔


bottom-right).

Backslash Diagonal Lookup array: Tracks anti-diagonals (top-right


➔ bottom-left).

Diagonal indexing formulas:


Slash Diagonal: row + col

Backslash Diagonal: row - col + (N-1)

Using these formulas, we can quickly find if a diagonal is already


occupied.

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.

Important Viva Questions (with Answers)


Q1. What is the N-Queens problem?
Ans:It is the problem of placing N queens on an N×N chessboard so
that no two queens threaten each other.

Q2. What strategies are used to solve the N-Queens problem?


Ans:We use Backtracking (try and undo) and Branch and Bound
(prune invalid paths early).

Q3. What are the conditions to check before placing a queen?


Ans: No queen in the same row.
No queen in the same slash diagonal (row + col).
No queen in the same backslash diagonal (row - col + (N-1)).

Q4. What is backtracking?


Ans:Backtracking is a technique where we try to build a solution
step-by-step and undo the last step if it leads to a dead-end.

Q5. What is branch and bound?


Ans:Branch and Bound is an optimization over backtracking that
prunes unnecessary branches if it is clear that they won't lead to a
valid solution.

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.

Q7. How are diagonals represented mathematically?


Ans: Slash diagonal ( / ): row + col
Backslash diagonal ( \ ): row - col + (N-1)

Q8. What is the time complexity of the N-Queens solution?


Ans:The time complexity is roughly O(N!) because we may have to
explore almost all permutations in the worst case.

Q9. How many solutions exist for the 8-Queens problem?


Ans:
There are 92 distinct solutions for 8-Queens.

Q10. Can the N-Queens problem be solved for any value of N?


Ans:
Yes, but:
For N=2 and N=3, no solution exists.
For N≥4, solutions exist.

Working of Your Code:


Initialize:
N = 8 (Default, but you can set any N)
Create a chessboard matrix of size N×N initialized to 0.
Create lookup arrays:
rowLookup[N] → Check if a row is already occupied.
slashDiagonalLookup[2N-1] → Check top-left to bottom-
right diagonals.
backSlashDiagonalLookup[2N-1] → Check top-right to
bottom-left diagonals.
Preprocess Diagonals:
Fill two matrices:
Slash diagonal (/): row + col
Backslash diagonal (\): row - col + (N-1)

Solve using Recursion:


Start placing queens column by column.
For each row in the current column:
Check if it's safe (using lookup tables).
If safe:
Place queen (set 1 in matrix).
Mark the row and diagonals as occupied.
Recurse to next column.
If placing a queen in this row leads to a dead-end:
Backtrack (remove queen, unmark row and diagonals).
If all queens are placed, print the solution.
Print Solution:
After placing all queens, the board is printed with 'Q' for
queens and '.' for empty spaces.

Key Points in Your Code:


Branching: Trying different rows for each column.
Bounding: Checking using lookup arrays before placing queens.
Backtracking: If no placement possible, undo last queen placement.
Efficiency: O(1) lookup for safe checks instead of O(N).

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

Important Viva Questions (Specific to Your File)


Q1. What is the objective of the N-Queens problem?
Ans:To place N queens on an N×N chessboard so that no two queens
attack each other (no same row, column, or diagonal).

Q2. What technique is used to solve the N-Queens problem in your


file?
Ans:
Backtracking and Branch and Bound are used.

Q3. What is the purpose of slashDiagonal and backSlashDiagonal


matrices?
Ans:
They help to quickly identify if a queen can be attacked along a
diagonal by mapping diagonals into simple array indexes.

Q4. What formulas are used to map diagonals?


Ans:

Slash Diagonal (/) → row + col

Backslash Diagonal (\) → row - col + (N-1)

Q5. What is the role of lookup arrays (rowLookup,


slashDiagonalLookup, backSlashDiagonalLookup)?
Ans:
They are used to quickly check if placing a queen is safe in O(1)
time.

Q6. Why is branch and bound more efficient than simple


backtracking?
Ans:
It prunes paths early where a solution is not possible, reducing
unnecessary recursion.
Q7. What is the time complexity of solving the N-Queens problem
using your approach?
Ans:
Approximately O(N!) because in the worst case, you may have to
try all possible placements.

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.

Q9. Why do we need (2N - 1) size arrays for diagonals?


Ans:
Because the number of possible diagonals in an N×N board is 2N-1.

Q10. What happens when the solution finds a dead-end?


Ans:
The algorithm backtracks by removing the last queen placed and
tries a new position.

1. Constraint Satisfaction Problem (CSP)


Definition:
A Constraint Satisfaction Problem (CSP) is a type of problem
where you need to assign values to a set of variables while satisfying
certain conditions (constraints).

Key parts of CSP:

Variables → The elements we need to assign values to.


Domains → The set of possible values each variable can take.

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

This is like coloring a map or placing queens on a chessboard — you


must choose carefully to satisfy all rules!

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.

Add one piece at a time.

If at any step, constraints are violated → Undo the last step


(backtrack) and try another possibility.

Example:
Place a queen in the first column.

Try a safe row.


If stuck later → Remove the queen and try the next row.

3. Branch and Bound


Definition:
Branch and Bound is an optimization over backtracking that cuts
off (prunes) paths that are definitely not going to lead to a valid
solution.

How it works:
Explore only promising branches.

If a partial solution already violates constraints, stop exploring


deeper from that branch.

Branch = A decision made (e.g., place a queen in a row).


Bound = A test to check if further exploration is worthwhile.

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:

No two queens are in the same row,

No two queens are in the same column,

No two queens are on the same diagonal.


How it is a CSP:
Variables → Positions of the queens.
Domain → Possible rows for each column.
Constraints → No same row, no same column, no same diagonal.
5. Other Basic Concepts (you should know)
✅ What is a solution in CSP?
A complete assignment of values to variables that satisfies all
constraints.
✅ What are Diagonals in N-Queens?
Slash diagonal (/): Moves top-left to bottom-right.
Backslash diagonal (\): Moves top-right to bottom-left.
Identified with:
Slash: row + column
Backslash: row - column + (N-1)
✅ Difference between Backtracking and Branch and Bound?
Feature Backtracking Branch and Bound
Search Method All possibilities Only promising possibilities
Prunes Dead Ends After full failure Early (during search)
Speed Slower Faster
Memory Usage Less More (may store more info)
✅ What is Pruning?
Pruning means cutting off a path early during search when you
know it can't lead to a solution.
✅ Where else are CSPs used?
Sudoku
Graph coloring
Crossword puzzles
Scheduling problems
Viva Ready Key Sentences (to Speak Smartly)
"The N-Queens problem is a classic example of a Constraint
Satisfaction Problem."
"Backtracking builds a solution incrementally and backtracks on
failure."
"Branch and Bound optimizes backtracking by pruning non-
promising branches early."
"Diagonals are identified using simple formulas: row + col, and row
- col + (N-1)."
"Constraint satisfaction involves variables, domains, and
constraints."
"Pruning saves time and speeds up the search for a solution."
import copy
import random

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

def solve(board, col, n):


#Use backtracking to find all solutions
if col >= n:
return

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"

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


#Check if it's safe to place a queen at board[x][y]
#check row on left side
for j in range(col):
if board[row][j] == "Q":
return False

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)

#Taking size of the chessboard from user


n = take_input()

#Returns a square board of nxn dimension


board = get_board(n)

#Empty list of all possible solutions


solutions = []

#Solving using backtracking


solve(board, 0, n)

print()

print("One of the solutions is: \n")


print_solution(solutions, n)

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:

Place N queens on an N×N chessboard.

No two queens can attack each other:

No two in the same row.

No two in the same column.

No two in the same left diagonal.

No two in the same right diagonal.

Backtracking Approach:

Solve column by column.

Place a queen in a column and move to the next.

If placing leads to a conflict, backtrack.

Use an 8x8 binary matrix to track safe cells.

Time complexity to check safe cell = O(N²).

Branch and Bound Approach:

Smarter backtracking.
Prune dead-end paths early (don’t explore further).


Maintain three boolean arrays:

rowFree[]: row availability.

o
o

slashCode[]: left-diagonal (top-left to bottom-right).

o
o

backSlashCode[]: right-diagonal (top-right to bottom-left).

Diagonal Calculation:

slashCode[row][col] = row + col


backSlashCode[row][col] = row - col + (N - 1)

1. Python Code: N-Queens using


Backtracking
python
CopyEdit
def print_board(board, n):
for i in range(n):
for j in range(n):
print('Q' if board[i][j] else '.', end=' ')
print()
print()
def is_safe(board, row, col, n):
# Check column
for i in range(row):
if board[i][col]:
return False

# Check left diagonal


i, j = row, col
while i >= 0 and j >= 0:
if board[i][j]:
return False
i -= 1
j -= 1

# Check right diagonal


i, j = row, col
while i >= 0 and j < n:
if board[i][j]:
return False
i -= 1
j += 1

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

for col in range(n):


if is_safe(board, row, col, n):
board[row][col] = 1
if solve_nqueens_backtrack(board, row + 1, n):
return True
board[row][col] = 0 # Backtrack

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)

✅ This solves 8-Queens using classic backtracking.

2. Python Code: N-Queens using


Branch and Bound
python
CopyEdit
def print_board(board, n):
for i in range(n):
for j in range(n):
print('Q' if board[i][j] else '.', end=' ')
print()
print()
def solve_nqueens_branchbound(board, row, n, left_row, lower_diag,
upper_diag):
if row == n:
print_board(board, n)
return True # Change to False if you want **all** solutions

for col in range(n):


if left_row[col] == 0 and lower_diag[row + col] == 0 and
upper_diag[n - 1 + col - row] == 0:
board[row][col] = 1
left_row[col] = lower_diag[row + col] = upper_diag[n - 1
+ col - row] = 1

if solve_nqueens_branchbound(board, row + 1, n, left_row,


lower_diag, upper_diag):
return True

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

solve_nqueens_branchbound(board, 0, n, left_row, lower_diag,


upper_diag)
# Example
n_queens_branch_and_bound(8)

✅ This solves 8-Queens using Branch and Bound (optimized checks).

Final Conclusion

You have learned how to solve n-Queens using both Backtracking and Branch
and Bound.


Branch and Bound is faster because it avoids unnecessary exploration by


maintaining additional arrays.


Both approaches correctly place queens such that no two attack each other.

⚡ Quick Difference Table


Aspect Backtracking Branch and Bound
Traverses all Prunes impossible paths
Checking
possibilities early
Time Slower Faster
Extra Data 3 Arrays (rows +
None
Structures diagonals)
What is a Chatbot?
A chatbot is a computer program designed to simulate conversation with human users over the
Internet. Also known as conversational agents, chatbots communicate through text or voice
interactions to accomplish specific tasks.
Chatbots mainly fall into two categories:

AI-based Chatbots: Learn from conversations and provide dynamic responses.

Scripted Chatbots: Follow a predefined conversational flow using multiple-choice options.

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.

Act as personal shopping assistants recommending products.

Engage users through marketing, promotions, and support.

Reduce operational costs for businesses.

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.

Handling Multiple Customers Simultaneously:


Unlike humans, bots can interact with thousands of customers simultaneously without errors.

Cost Savings:
Reduces the need for large customer support teams by automating basic queries.

100% Customer Satisfaction:


Bots provide consistent, polite, and helpful responses, unaffected by emotions or fatigue.

Automation of Repetitive Work:


Chatbots automate recurring tasks like notifications, reports, and reminders, improving productivity.

Acts as a Personal Assistant:


Fashion advisors, travel planners, finance bots — chatbots can personalize recommendations based on
user history and preferences.

How Chatbots Can Drive Revenue:


Higher User Engagement:
Bots help users find products, solve issues quickly, and increase the likelihood of return visits.

Mobile-Ready and Immediate Availability:


Bots work on messaging platforms without the need for users to install apps.

Sales Generation:
Chatbots can recommend products, offer discounts, and enable instant ordering over chat.

Minimal Cost, Maximum Return:


Bots require minimal maintenance and offer a high ROI compared to traditional service teams.

Improved Customer Service:


Track orders, handle returns, notify about back-in-stock products, and collect reviews efficiently.

Applications Across Industries:


Restaurants & Retail:
Automate food ordering and reservations.

Provide menus and delivery updates.

Hospitality & Travel:


Assist with hotel bookings, local travel recommendations, and support multiple languages.

Healthcare:
Answer health-related queries.

Offer instant support and health tips without waiting for a doctor.

E-commerce:
Personalized shopping experiences.

Send product recommendations and enable purchases through chat.

Fashion Industry:
Offer personal styling recommendations.

Track customer preferences and suggest items accordingly.

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 greet(bot_name, birth_year):


print("Hello! My name is {0}.".format(bot_name))
print("I was created in {0}.".format(birth_year))

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

print("Your age is {0}; that's a good time to start


programming!".format(age))

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

print('Completed, have a nice day!')


print('.................................')
print('.................................')
print('.................................')

def end():
print('Congratulations, have a nice day!')
print('.................................')
print('.................................')
print('.................................')
input()

greet('Prakash','2024') # change it as you need


remind_name()
guess_age()
count()
test()
end()

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.

Purpose: Users can deploy applications without managing hardware.

Billing: On-demand instances charge per hour based on selected


instance type.

Infrastructure: EC2 instances are deployed inside VPCs (Virtual


Private Clouds), secured with Security Groups, and scalable using
Auto Scaling Groups.

Use Cases: Application hosting, ML model deployment, gaming


servers, hybrid cloud architecture.

Major Benefits: Cost efficiency, scalability, flexibility, ease of


deployment.

Important Points to Know (Exam/Interview Ready)


Elastic Compute Cloud (EC2): AWS service offering resizable
compute capacity in the cloud.

On-Demand Instance: Pay for compute capacity by the hour or


second with no long-term commitments.

Scaling: Auto-scaling adjusts the number of instances according to


load (scale up/down).
Security: Achieved through VPC, subnets, and security groups.

Key Pair: Required for securely connecting (SSH for Linux or RDP
for Windows instances).

Instance Pricing: Depends on instance type (CPU, memory, network


capabilities).

Simple, Correct Working Steps


(For: "Create and Configure an Amazon EC2 Instance on AWS")

1. Login to AWS
Go to AWS Management Console → Sign in as Root User.

Enter credentials → Next → Home Page.

2. Select AWS Region


In the top right, choose the AWS region closest to your users.

3. Launch a New Instance


Click Launch Instance from the EC2 Dashboard.

4. Create a Key Pair (Security)


Click Create New Key Pair.

Name it (e.g., MyKeyPair).

Select .pem format.

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

Choose Instance Type: (e.g., t2.micro = free tier eligible).

Configure Instance: Leave default unless needed.

Add Storage: Accept default or increase size.

Add Tags: (Optional) Add Name tag.


Configure Security Group: Create new or select existing. Open ports
like SSH (port 22 for Linux) or RDP (port 3389 for Windows).

6. Launch
Select your previously created Key Pair.
Click Launch Instance.
Instance will start provisioning.

7. Connect to the Instance


After instance is running:

Select Instance → Click Connect.

For Windows Instance:

Click RDP Client → Download Remote Desktop File.

Click Get Password, upload your .pem file → Decrypt → Copy


Password.
Open downloaded RDP file → Paste password → Connect.
For Linux Instance:
Open Terminal:
chmod 400 MyKeyPair.pem
ssh -i "MyKeyPair.pem" ubuntu@<your-public-ip>

8. (Optional) Stop Instance to Save Cost


After usage, Stop the instance to avoid being charged.

Conclusion
EC2 instances let you easily deploy, scale, and manage applications
without buying physical servers.
Manage costs by stopping or terminating unused instances.

1. What is Amazon EC2?


Answer:
Amazon EC2 (Elastic Compute Cloud) is a web service that provides resizable, scalable compute
capacity in the AWS Cloud. It allows users to run virtual servers without maintaining physical
hardware.

2. What does "Elastic" mean in EC2?


Answer:
"Elastic" means you can easily scale your compute resources up or down based on your application's
demand.

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.

4. What is a Key Pair in AWS EC2?


Answer:
A Key Pair is a combination of a public key and a private key used to securely connect to an EC2
instance. The private key (.pem file) must be downloaded and kept safely.

5. What is a Security Group in EC2?


Answer:
A Security Group acts as a virtual firewall for your EC2 instance, controlling incoming and outgoing
traffic based on rules you define (e.g., allow SSH port 22, RDP port 3389).

6. What is an On-Demand EC2 Instance?


Answer:
An On-Demand EC2 Instance lets users pay for compute capacity by the hour or second, with no
long-term commitment. It is flexible and ideal for unpredictable workloads.

7. How do you connect to a Linux EC2 instance?


Answer:
Using SSH command in terminal:
chmod 400 MyKeyPair.pem
ssh -i "MyKeyPair.pem" ubuntu@<public-ip>

8. How do you connect to a Windows EC2 instance?


Answer:
Download the Remote Desktop (.rdp) file.
Decrypt the administrator password using the Key Pair (.pem file).
Open the .rdp file, paste the password, and connect.

9. What happens if you lose the .pem Key Pair file?


Answer:
You cannot connect to the instance anymore. The recommended action is to create a new instance or
create a backup AMI before losing access.

10. What is the purpose of stopping an EC2 instance?


Answer:
Stopping an instance halts it without terminating. You are not charged for compute (CPU/RAM)
when stopped, but you might still pay for attached storage (EBS volume).

11. What are some common use cases of EC2?


Answer:
Hosting websites and applications
Deploying Machine Learning models
Running enterprise applications
Gaming server hosting
Hybrid cloud setups with on-premises systems

12. Difference between Stopping and Terminating an instance?


Answer:

Stop: Halts the instance; data on EBS is preserved.

Terminate: Deletes the instance and its attached storage (unless EBS is configured to persist).

13. Why do we select a region before launching an EC2 instance?


Answer:
Regions determine the physical location of your instance. Selecting the closest region reduces latency
and can impact compliance and pricing.

14. What is Auto Scaling in AWS EC2?


Answer:
Auto Scaling automatically adjusts the number of EC2 instances based on traffic load, ensuring high
availability and cost efficiency.
If they ask you: "Why use EC2 instead of buying your own servers?", answer:
No hardware maintenance.
Pay only when needed (no upfront CAPEX).
Immediate scalability.
High availability and disaster recovery built-in.

Google App Engine (GAE) = Fully managed PaaS (Platform as a Service).

Hosts web apps and mobile backends.

Supports automatic scaling → more users = more resources allocated automatically.

Combines IaaS + PaaS + SaaS → complete cloud platform.

Key Features:

High security (uses Google’s secure infrastructure).

Global availability (Google's worldwide server network).

Auto-scaling and load balancing.

Data storage, computation, management built-in.

Use cases:
SMEs, Enterprises needing to scale web apps without worrying about infrastructure.

Advantages:
Top-notch security (Google-grade).

Automatic scaling (small to millions of users).

Reliable performance (Google infrastructure).

Easy app development with SDKs and cloud tools.

Working + Simplified Installation and Configuration Steps


✅ Step-by-Step Procedure:
1. Sign Up
Visit Google Cloud Console.

Sign up or log in with Google account.

2. Create New Project


Click "New Project".
Name your project → Click "Create".
3. Access Cloud Overview
Click the "Navigation Menu" (☰) → Select "Cloud Overview → Dashboard".

4. Enable App Engine Admin API


In Search bar, type "App Engine Admin API".

Click it → Press "Enable".

5. Activate Cloud Shell


On top-right, click the ">_" button to open Cloud Shell (online terminal).

6. Clone GitHub Repository


Open the desired GitHub repo → Copy its HTTPS URL.

In Cloud Shell, type:


git clone <copied link>
Example:
git clone https://github.com/rushu123/spos.git
7. Navigate to Project Folder
List files:
ls
Move into repo:
cd <repository name>
Example:
cd spos
8. Run Your Program
For Java Program:
Compile:
javac <programname.java>
Example:
javac firstfit.java
Run:
java <programname>
Example:
java firstfit

For Python Program:


Run:
python <programname.py>
Example:
python hello.py
✅ Conclusion:
Thus, we have successfully installed and configured Google App Engine, created a project, and
deployed/runned sample applications.

Quick Tips for Viva/Practical:


What is GAE? → A managed cloud platform to run scalable web/mobile apps.
Major Benefit? → Auto-scaling without worrying about infrastructure
Which cloud model? → PaaS (Platform as a Service).
Command to clone repo? → git clone <url>
Command to run Java program? → javac file.java && java file
Command to run Python program? → python file.py

1. What is Google App Engine (GAE)?


✅ Answer:
Google App Engine is a Platform-as-a-Service (PaaS) cloud platform that allows developers to build,
deploy, and scale web applications easily without managing underlying infrastructure (like servers,
databases, etc.).

✅ 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.

2. Features of Google App Engine?


✅ Answer:
Automatic Scaling: Handles any number of users dynamically.
Built-in Services: Datastore (DB), Memcache, User Authentication.
Multiple Language Support: Python, Java, Node.js, PHP, Go, Ruby.
Versioning: Multiple app versions can be deployed and managed.
Security: Uses Google’s global secured network.

3. Advantages of Google App Engine?


✅ Answer:
No Server Management needed (fully managed platform).
Automatic load balancing and failover handling.
Pay-as-you-go model — cost-efficient.
Built-in security and identity management.
Easy integration with other Google Cloud services (Cloud SQL, Cloud Storage, BigQuery).

4. Difference between IaaS, PaaS, and SaaS?


(VERY important — viva favorite)

Model Meaning Example Responsibility


Infrastructure as AWS EC2, Google User manages OS,
IaaS
a Service Compute Engine middleware, runtime, apps
Google App Engine, User manages only code;
Platform as a
PaaS AWS Elastic cloud manages everything
Service
Beanstalk else
Software as a Everything managed by
SaaS Gmail, Google Docs
Service cloud provider

Summary:

IaaS: You rent servers.


PaaS: You rent a runtime environment.

SaaS: You rent finished software.

5. Why is scalability important in cloud applications?


✅ Answer:

Scalability allows applications to handle increased user load without failure.

In GAE, scalability is automatic: more users → more resources allocated instantly.

No manual server upgrades or downtime needed.

✅ Example:
If your app has 10 users today and 10 million users tomorrow, GAE can handle it without needing
you to add servers manually.

6. Steps to deploy an app on Google App Engine (Summary)?


✅ Answer:
Create a Google Cloud project.
Enable App Engine Admin API.
Setup Cloud Shell or SDK.
Prepare your code.
Deploy app using:
gcloud app deploy

Viva Questions Set

Sr Viva Question Model Answer (Short Version)


It is a fully managed PaaS platform
1 What is Google App Engine? to run scalable web apps and
services.
No server management, automatic
2 Why use Google App Engine? scaling, reliable Google
infrastructure.
What language can you use Python, Java, Node.js, PHP, Go, Ruby,
3
with GAE? and others.
What is the role of App It manages your app’s services,
4
Engine Admin API? scaling, and settings.
A browser-based Linux shell provided
5 What is Cloud Shell?
by Google Cloud for running commands.
What command is used to
6 git clone <repository-url>
clone a GitHub repo?
How do you compile and run a Compile with javac filename.java, run
7
Java program in Cloud Shell? with java filename.
8 How do you run a Python Use python filename.py
Sr Viva Question Model Answer (Short Version)
script in Cloud Shell?
What are the advantages of Scalability, security, reliability,
9
GAE? easy integration, pay-as-you-go.
IaaS gives servers; PaaS gives a
What is the difference
10 ready environment to just deploy
between IaaS and PaaS?
code.

Concept 1-Line Memory Tip


GAE Cloud platform to run apps with no server headache.
Scaling GAE auto-scales as users increase.
PaaS Only code is your responsibility, not infra.
Git Clone Copies project from GitHub to your cloud machine.
Cloud Shell Browser terminal inside Google Cloud.

Create an Application in Salesforce.com using Apex Programming Language.


Objective:
Learn how to build and run a simple application (sending an email) inside Salesforce using Apex
code.
Background:
Salesforce is a cloud-based CRM (Customer Relationship Management) platform.

Key Salesforce features:


Contact Management: Track customer information and communication.
Opportunity Management: Track deals and sales pipeline.
Sales Collaboration: Team collaboration for closing deals.
Sales Performance Management: Goal tracking and rewarding sales teams.
Workflow and Approvals: Automate processes visually.
Mobile App & Email Integration: Access anywhere, integrate with email systems.

Step-by-Step Execution
Step 1: Login
Open Salesforce Developer → Login to your account.

Step 2: Open Developer Console


In Salesforce Lightning Platform:
→ Click Setup (Gear Icon) → Select Developer Console.

Step 3: Create a New Apex Class


In Developer Console:
→ File → New → Apex Class
→ Name it something like EmailManager → Click OK.

Step 4: Write This Apex Code


Paste exactly this code inside the class:
public class LS{
public static void demo(Integer key){
System.debug('Linear Search');
integer s=-1;
List<integer> lon=new List<integer> ();
lon.add(3);
lon.add(4);
lon.add(5);
lon.add(6);
System.debug('List: '+lon);
for(integer i=0;i<lon.size();i++){
if(key==lon[i]){
s=1;
}
}
if(s==1){
System.debug('Element found');
}
else{
System.debug('Element NOT found');
}
}
}

Step 5: Open Anonymous Execution Window


In Developer Console:
→ Click Debug → Open Execute Anonymous Window.

Step 6: Write This Execution Code


LS.demo(3);
LS.demo(2);

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.

2. What is Apex in Salesforce?


Answer:
Apex is a strongly typed, object-oriented programming language used in Salesforce to write custom
backend code like triggers, classes, and controllers. It is hosted on the Salesforce server and closely
resembles Java.

3. Why do we need Apex programming in Salesforce?


Answer:
We use Apex to:

Create custom business logic.


Automate complex processes beyond point-and-click tools (like Workflow Rules or Flows).
Integrate Salesforce with external systems via APIs.
Build custom applications (like the Email Application we created).

4. What is a Developer Console in Salesforce?


Answer:
The Developer Console is a browser-based integrated development environment (IDE) provided by
Salesforce. It allows developers to:
Create/modify Apex classes and triggers.
Execute anonymous Apex code.
View debug logs.
Test and deploy code easily.

5. What is an Apex Class?


Answer:
An Apex Class is a template or blueprint that defines methods (functions) and variables. It groups
related logic together and is the basic building block for coding in Salesforce.
In our experiment, the EmailManager class defines a method sendMail() to send emails.

6. What is Messaging.SingleEmailMessage class?


Answer: Messaging.SingleEmailMessage is a built-in Apex class provided by Salesforce to create and
send a single email through Apex code.
It allows setting:
Recipient address,
Subject,
Body content.

7. What is Execute Anonymous Window?


Answer:
It’s a special tool inside the Developer Console where you can run Apex code without needing to
attach it to a trigger or class permanently.
Used mainly for testing small pieces of code or executing on-the-fly scripts.

8. What happens if there is a syntax error in Apex code?


Answer:
Salesforce's Developer Console will show a compilation error immediately when you try to save or
execute the code. Apex must compile successfully before it can run.

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.

10. How is an Apex Class executed?


Answer:
You create the class → Save it → Then either call its methods:
From Execute Anonymous Window,
Or link it to UI elements like a button,
Or schedule/trigger it based on events.
In the lab, we executed it manually through Execute Anonymous Window.

DEEP EXPLANATION OF IMPORTANT CONCEPTS


What is Apex?
Apex runs natively on Salesforce servers → It has built-in multi-tenancy (sharing resources securely).
Syntax is Java-like: Classes, Objects, Methods, Variables, If-else, Loops.
Has limits called Governor Limits to prevent bad code from overusing shared cloud resources.

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.

Sending Email via Apex


Salesforce internally handles SMTP email sending.
You use classes like Messaging.SingleEmailMessage or Messaging.MassEmailMessage for different needs.
You must provide:
Recipient address(es)
Subject
Plain Text or HTML Body
Salesforce enforces daily limits on how many emails you can send from Apex to avoid spam.

Anonymous Window Importance


Allows quick testing without deploying code.
You can instantiate classes, call methods, and run logic without building full applications.
Helps in debugging small parts of logic quickly.

RAPID FIRE MINI FAQ (Extra Level


Preparation)
Question Quick Answer
Can we send attachments
Yes, using setFileAttachments() method.
in email?
Can we send emails to Yes, using an array inside
multiple recipients? setToAddresses().
What if email fails to Salesforce will throw an exception you can
send? catch using try-catch blocks.
Is Apex compiled or Apex is compiled into bytecode on
interpreted? Salesforce servers before execution.
What is Governor Limit 5,000 email messages per day per org (for
for emails? most editions).
FINAL PRO GOD SCHOLAR TIP:
When answering viva, speak using keywords like:
"Cloud-based CRM",
"Metadata-driven architecture",
"Strongly typed Apex code",
"Anonymous execution",
"Messaging class for emails",
"Multi-tenant secure environment".

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

String subject = 'Speaker Confirmation';


String address = '[email protected]';
String body = 'Thank you for attending the conference.';
EmailManager.sendMail(address, subject, body);

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.

App = Collection of tabs and functionality bundled together as a working application.

Simple, Correct Working Steps:


(Step-by-step so you can complete your Mini Project perfectly)

1. Login to Salesforce
Go to Salesforce login.

Enter your credentials and open Home Page.

2. Create Custom Objects


Click on Object Manager (top menu).

Click Create → Custom Object.

Create a new object:

Example:
Label: Stud
Plural Label: Studs

Click Save and New to create another.

Create second object:

Example:
Label: Read_Books
Plural Label: Read_Books

Save.

✅ Now, you have two custom objects: Stud and Read_Books.

3. Add Fields to Objects


Go to Object Manager → select Stud.

Click Fields and Relationships → New.

Choose Text type → Click Next.

Create a field:

Example Field Name: Class


Click Next → Next → Save.

Repeat for Read_Books:

Example Field Name: Book_Name

4. Create Tabs for Objects


Go to Setup (gear icon, top-right).

Search for Tabs.

Click New Tab.

Choose:

Object: Stud

Tab Style: (choose any icon style)

Click Next → Next → Save.

Repeat for Read_Books object.

5. Create a New Application


Go to Setup → Search App Manager.

Click New Lightning App.

Fill Details:

App Name: (example) LMS

Click Next.

Add Navigation Items (Tabs):

Add tabs for Stud and Read_Books.

Click Next until you reach User Profiles.

Select System Administrator profile.

Click Save and Finish.

6. View Your Application


Click App Launcher (grid icon on top left).

Search for your app (example: LMS).


Open and check if:

Stud and Read_Books tabs are visible.

You can add records in both objects.

✅ Congratulations! Your custom Salesforce Cloud Application is built.

Final Recap:

Step Action Important Tip


1 Login to Salesforce Setup account if needed
2 Create Custom Objects Stud, Read_Books
3 Add Fields Use Text fields
4 Create Tabs Makes objects visible
5 Build App (Lightning App)Add both tabs
6 Launch and Verify App Check in App Launcher

You might also like