Complete Detailed Solutions · Important Questions
1. Merge sort is based on
Answer: b) Divide and conquer
2. Prim's algorithm is used to find
Answer: b) MST (Minimum Spanning Tree)
3. DFS uses
Answer: b) Stack
4. In dynamic programming, solutions are stored in
Answer: b) Table/Memorization
5. Topological sorting is applicable to
Answer: b) Directed acyclic graph (DAG)
6. Greedy algorithms always make
Answer: b) Optimal local choice
7. Binary search works only on
Answer: b) Sorted array
8. Recurrence relation is used in
Answer: b) Divide and conquer
9. Bellman-Ford algorithm can detect
Answer: b) Negative weight cycles
10. Relaxation in shortest path algorithms means
Answer: b) Updating minimum distance
11. Kruskal's algorithm is a
Answer: b) Greedy algorithm
12. Which of the following algorithm is used to find the all pair shortest path problem?
Answer: c) Floyd's Algorithm
13. The example of a non-comparison-based sorting technique is
Answer: d) Bucket sort
14. Lower bound of any comparison-based sorting algorithm is
Answer: d) O(n log n)
15. The Big-O notation of the expression f(n) = n² + n log n + 1 is
Answer: a) O(n²)
16. Bellman-Ford requires how many iterations over edges?
Answer: b) V-1
17. Consider a graph G=(V, E), V = {v1...v100}, E={(vi, vj) | i < j}. Weight of edge is |i-j|. Weight of MST is:
Answer: a) 99. The graph is complete, and taking edges (v1,v2), (v2,v3)...(v99,v100) all with weight 1 gives an MST of weight 99.
18. Relationship between O(n) and Ω(n)?
Answer: d) There's no relationship between O(n) and Ω(n) (One is upper bound, the other is lower bound).
19. A graph with no cycles is called
Answer: b) Acyclic graph
20. Best case of merge sort is
Answer: b) O(n log n)
21. Algorithm design technique for all pairs of shortest distances
Answer: a) Dynamic programming (Floyd-Warshall is DP).
22. To implement Dijkstra's on unweighted graphs in linear time, data structure is:
Answer: a) Queue (Essentially becoming BFS).
23. Data structure useful for BFS
Answer: c) Queue
24. O(1) means computing time is
Answer: a) Constant
25. Which of the following is true
Answer: a) P is subset of NP
26. Properties of a dynamic programming problem?
Answer: d) Both optimal substructure and overlapping sub problems
27. In the context of 0/1 Knapsack, a 'feasible solution' is
Answer: a) Any solution that does not exceed the knapsack's capacity.
28. Time complexity of Floyd-Warshall algorithm
Answer: d) O(V³)
29. Main purpose of branch and bound
Answer: c) Both A and B (Find best solution and eliminate non-promising solutions).
30. Which type of search is typically used in the branch and bound algorithm?
Answer: b) Breadth-first search (or Best-First Search)
Minimum Spanning Tree (MST): Given a connected, undirected, and weighted graph \(G = (V, E)\), a spanning tree is an acyclic subgraph that connects all the vertices in the graph. The Minimum Spanning Tree is a spanning tree whose sum of edge weights is minimized. Key properties of an MST include:
Differences between Prim's and Kruskal's Algorithms:
| Parameter | Prim's Algorithm | Kruskal's Algorithm |
|---|---|---|
| Basic Approach | Grows the tree by starting from an arbitrary root vertex and adding the nearest unvisited vertex at each step (vertex-centric). | Grows the forest by sorting all edges and adding the smallest edge that does not create a cycle (edge-centric). |
| Intermediate State | The intermediate structure is always a single connected tree. | The intermediate structure can be a disconnected forest of trees that merge over time. |
| Data Structures | Uses a Min-Priority Queue (Binary or Fibonacci Heap) to retrieve the next minimum-weight edge. | Uses a Disjoint-Set (Union-Find) data structure to check for cycles and sort the edges. |
| Cycle Detection | No explicit cycle detection is needed, as it only adds edges to unvisited vertices. | Explicit cycle detection is required, handled efficiently using the Union-Find data structure. |
| Suitability | Highly suitable for dense graphs (where \(E \approx V^2\)). | Highly suitable for sparse graphs (where \(E \approx V\)). |
| Time Complexity |
|
\(O(E \log E)\) or \(O(E \log V)\) due to sorting of edges. |
Dynamic Programming (DP): An algorithmic paradigm that solves a complex problem by breaking it into overlapping subproblems, solving each subproblem exactly once, and storing their solutions (in a table) to avoid redundant computations. It is built on two primary principles:
Differences from the Greedy Method:
| Criteria | Dynamic Programming | Greedy Method |
|---|---|---|
| Choice Selection | Evaluates all possible options at each stage and chooses the global optimum. Past decisions can be reconsidered. | Makes the local optimal choice at each step without looking ahead or reconsidering past choices. |
| Optimality | Always guarantees a global optimal solution (provided optimal substructure exists). | Does not always guarantee a global optimal solution (though it works for specific problems like Fractional Knapsack). |
| Subproblem Dependency | Subproblems are highly overlapping. Solutions are built bottom-up (tabulation) or top-down (memoization). | Subproblems are solved sequentially. No overlapping subproblems are required. |
| Efficiency | Generally slower and computationally heavier, but polynomial in time. | Generally faster and much simpler (often \(O(n)\) or \(O(n \log n)\)). |
| Memory Overhead | High memory overhead due to storing subproblem solutions in a DP table or memoization map. | Low memory overhead as it doesn't need to maintain a state table. |
int fun(int n) {
int count = 0;
for (int i = n; i > 0; i /= 2) {
for (int j = 0; j < i; j++) {
count += 1;
}
}
return count;
}
Mathematical Analysis:
i = n and halves it in each iteration (i /= 2) until i <= 0. The sequence of values of i is: \(n, n/2, n/4, n/8, \dots, 1\).i times for each value of i in the outer loop (from j = 0 to j < i - 1).count += 1) is the sum of the inner loop counts across all iterations:
Asymptotic Notations represent the rates of growth of algorithms. Big-O and Omega notation serve as upper and lower bounds respectively.
| Property | Big-O (O) Notation | Omega (Ω) Notation |
|---|---|---|
| Definition | Represents the asymptotic upper bound of an algorithm's time complexity. It describes the worst-case scenario. | Represents the asymptotic lower bound of an algorithm's time complexity. It describes the best-case scenario. |
| Mathematical Definition | \(f(n) = O(g(n))\) if there exist positive constants \(c\) and \(n_0\) such that: \(0 \le f(n) \le c \cdot g(n)\) for all \(n \ge n_0\). |
\(f(n) = \Omega(g(n))\) if there exist positive constants \(c\) and \(n_0\) such that: \(0 \le c \cdot g(n) \le f(n)\) for all \(n \ge n_0\). |
| Graphical Behavior | The function \(c \cdot g(n)\) lies above or on \(f(n)\) for all sufficiently large \(n\). | The function \(c \cdot g(n)\) lies below or on \(f(n)\) for all sufficiently large \(n\). |
| Use Case | Provides a guarantee that the algorithm will not take longer than this time. | Provides a guarantee that the algorithm will take at least this much time. |
Example (Insertion Sort):
Problems Solved by Dynamic Programming: DP is applicable to optimization problems that exhibit two critical properties:
Common examples include: Matrix Chain Multiplication (MCM), Longest Common Subsequence (LCS), 0/1 Knapsack, Bellman-Ford (Single-source shortest path with negative edges), and Floyd-Warshall (All-pairs shortest path).
Can we solve All-Pairs Shortest Path (APSP) using Dijkstra's Algorithm?
Yes, we can solve APSP by running Dijkstra's algorithm \(|V|\) times, using each vertex as the source once. Let's analyze the properties of this approach:
Given matrices \(A_1(2 \times 3)\), \(A_2(3 \times 4)\), and \(A_3(4 \times 5)\), the dimensions array is \(P = [2, 3, 4, 5]\) with \(n = 3\) matrices. The cost recurrence relation is:
Step-by-Step DP Computation:
The Ford-Fulkerson Algorithm computes the maximum possible flow in a flow network from a source node \(S\) to a sink node \(T\). It works by repeatedly finding "augmenting paths" in the "residual graph" and adding their bottleneck capacities to the total flow.
Ford-Fulkerson(Graph G, Node S, Node T):
1. Initialize flow f(u, v) = 0 for all edges (u, v) in G
2. Construct the residual graph G_f where:
- Forward edge capacity: c_f(u, v) = c(u, v) - f(u, v)
- Reverse edge capacity: c_f(v, u) = f(u, v)
3. While there exists a path P from S to T in G_f such that c_f(u, v) > 0 for all (u, v) in P:
a. Find the bottleneck capacity of the path:
c_f(P) = min { c_f(u, v) : (u, v) is in P }
b. Update flow along path P:
For each edge (u, v) in P:
If (u, v) is a forward edge in G:
f(u, v) = f(u, v) + c_f(P) // Augment flow
Else:
f(v, u) = f(v, u) - c_f(P) // Decrease reverse flow (push back)
c. Update the capacities in the residual graph G_f
4. Return the maximum flow (sum of flow leaving source S)
Time Complexity Analysis:
The recurrence relation is \(T(n) = 2T(n/2) + n \log n\). We compare this with the standard Master's Theorem form:
Here, we identify:
Step 1: Compute \(n^{\log_b a}\)
\[n^{\log_b a} = n^{\log_2 2} = n^1 = n\]
Step 2: Compare \(f(n)\) with \(n^{\log_b a}\)
We notice that \(f(n) = n \log n\) grows faster than \(n\), but not by a polynomial factor. It matches the Extended Case 2 of the Master Theorem:
If \(f(n) = \Theta(n^{\log_b a} \log^k n)\) for some \(k \ge 0\):
According to this case, the solution is:
\[T(n) = \Theta(n^{\log_b a} \log^{k+1} n)\]
Substituting the values:
\[T(n) = \Theta(n^1 \log^{1+1} n) = \Theta(n \log^2 n)\]
The Activity Selection Problem is a classic optimization problem. Given \(n\) activities with start times \(S[i]\) and finish times \(F[i]\), we want to find the size of the largest subset of mutually compatible activities (where no two selected activities overlap).
This is solved optimally using a Greedy Algorithm: we sort activities by finish times, then greedily pick the next compatible activity that finishes earliest.
Activity-Selection(Start[], Finish[], n):
1. Sort the activities according to their finish times in ascending order.
Assume the sorted activities are A_1, A_2, ..., A_n.
2. Select the first activity A_1 (it has the earliest finish time).
Print/Store A_1.
3. Initialize last_selected_finish = Finish[1]
4. For i = 2 to n:
a. If Start[i] >= last_selected_finish:
i. Activity A_i is compatible. Select it.
ii. Update last_selected_finish = Finish[i]
5. Return the list of selected activities.
Complexity Analysis:
Why this Greedy Strategy is Optimal: Picking the activity that finishes first leaves the maximum possible resource window open for subsequent activities, guaranteeing an optimal choice (Greedy Choice Property).
Differences between Dynamic Programming and Divide & Conquer:
| Feature | Dynamic Programming | Divide and Conquer |
|---|---|---|
| Subproblem Relationship | Solves problems with overlapping subproblems. Subproblems share results. | Solves problems with independent (disjoint) subproblems. Subproblems do not share results. |
| Redundant Work | Avoids redundant work by storing results in a table (memoization/tabulation). | May recalculate the same subproblems repeatedly if they happen to overlap (e.g., naive recursive Fibonacci). |
| Structure | Typically built bottom-up or top-down with memoization. | Strictly top-down recursion (Divide, Conquer, and Combine). |
| Memory Usage | High memory requirements to hold the lookup tables. | Low memory overhead, utilizing only the execution call stack. |
| Examples | Matrix Chain Multiplication, Floyd-Warshall, Edit Distance. | Merge Sort, Quick Sort, Binary Search. |
Greedy Algorithm Definition:
A greedy algorithm is an algorithmic paradigm that builds a solution step-by-step, making the locally optimal choice at each stage in the hope that this choice will lead to a globally optimal solution. It is characterized by two key properties: Greedy Choice Property (a global optimum can be reached by making local choices) and Optimal Substructure. Once a greedy choice is made, it is never revised (no backtracking), making it fast but not universally applicable.
Backtracking: Backtracking is an algorithmic technique for solving constraint-satisfaction problems by searching a state-space tree incrementally. It builds candidate solutions step-by-step. As soon as it determines that a partial candidate cannot possibly be extended to a valid complete solution, it abandons it ("backtracks") to the previous decision point.
Relationship to Recursion: Backtracking is fundamentally implemented using recursion. The recursive function calls represent deeper levels of exploration in the state-space tree. The activation records on the call stack keep track of the path from the root node. When a dead-end is hit, returning from a recursive function call naturally cleans up local states and steps back up the tree, making backtracking highly clean to express recursively.
Differences between Backtracking and Branch & Bound:
| Characteristic | Backtracking | Branch and Bound |
|---|---|---|
| Search Space Traversal | Traverses using Depth-First Search (DFS). | Traverses using Breadth-First Search (BFS) or Best-First Search. |
| Problem Type | Used for decision, game-playing, and constraint satisfaction problems (e.g., finding *any* or *all* valid states). | Used exclusively for optimization problems (finding the single global minimum/maximum cost path). |
| Pruning Mechanism | Prunes a path when a hard constraint is violated (feasibility test). | Prunes a path when its estimated cost (bound) is worse than the cost of the best solution found so far. |
| Data Structure | Uses a LIFO Stack (implicitly via recursion). | Uses a FIFO Queue or a Priority Queue (Min-Heap) to track active nodes. |
| Memory Overhead | Very low space complexity (\(O(d)\) where \(d\) is max depth). | Very high space complexity because it keeps many open nodes in memory. |
Single Source Shortest Path (SSSP): Given a weighted graph \(G = (V, E)\) (directed or undirected) and a designated source vertex \(S \in V\), the SSSP problem is to find the path of minimum total weight from \(S\) to every other vertex \(v \in V\). The path weight is defined as the sum of all individual edge weights along that path.
When does the Shortest Path NOT exist?
A shortest path from a source vertex \(S\) to a destination vertex \(D\) is undefined/does not exist in the following conditions:
Characteristics of Greedy Algorithms:
Why Greedy Fails for the 0/1 Knapsack Problem:
In the 0/1 Knapsack, an item must be chosen in its entirety or left behind (no fractional items allowed). When we make choices greedily based on the highest profit-to-weight ratio, we might leave empty space in the knapsack that cannot be filled, making the total value suboptimal. A non-greedy combination of items with lower individual ratios might fill the knapsack capacity perfectly and yield a higher overall profit.
Example Counter-Example:
Greedy choice picks Item A first (highest ratio 10). Remaining capacity = 4 kg. Neither B nor C can fit. Total profit = \$60.
Optimal choice picks Item B and Item C. Total weight = 10 kg, Total profit = \$45 + \$45 = \$90. This proves greedy fails.
Quick Sort is based on the Divide and Conquer strategy. The time complexity depends heavily on how balanced the partitions are after selecting a pivot.
1. Best Case Analysis:
Occurs when the pivot selection always splits the array into two equal halves of size \(n/2\) at each level of recursion. The recurrence relation is:
\[T(n) = 2T(n/2) + \Theta(n)\]
Where \(\Theta(n)\) represents the partition time. Using the Master's Theorem:
2. Worst Case Analysis:
Occurs when the pivot is always the smallest or largest element, splitting the array into partitions of size \(0\) and \(n-1\). This happens if the array is already sorted and we choose the first or last element as pivot. The recurrence relation is:
\[T(n) = T(n-1) + T(0) + c \cdot n = T(n-1) + c \cdot n\]
We solve this using the substitution method:
Since the highest term is quadratic, the complexity is:
The Floyd-Warshall Algorithm is a dynamic programming algorithm that finds the shortest paths between all pairs of vertices in a weighted directed graph. It supports positive and negative edge weights, but must not contain negative cycles.
DP Formulation: Let \(d_{ij}^{(k)}\) be the weight of the shortest path from vertex \(i\) to vertex \(j\) using only vertices in the set \(\{1, 2, \dots, k\}\) as intermediate nodes. The recurrence relation is:
Algorithm Pseudocode:
Floyd-Warshall(Graph W, V):
1. Let D^(0) be the initial V x V weight matrix where:
D^(0)[i][j] = 0 if i == j
D^(0)[i][j] = weight(i,j) if edge (i,j) exists
D^(0)[i][j] = Infinity if no edge exists
2. For k = 1 to V: // k represents the intermediate vertex
For i = 1 to V: // i is the source vertex
For j = 1 to V: // j is the destination vertex
D^(k)[i][j] = min( D^(k-1)[i][j], D^(k-1)[i][k] + D^(k-1)[k][j] )
3. Return D^(V) // Contains all-pairs shortest path distances
Complexity Analysis:
We solve the Fractional Knapsack Problem using the Greedy Approach. We are given capacity \(M = 10\) kg and five items with weights \(W\) and profits \(P\).
Step 1: Calculate Profit-to-Weight ratios (\(P_i / W_i\))
Step 2: Sort items in descending order of ratios
Order: Item 5 (8.00) \(\to\) Item 2 (5.00) \(\to\) Item 3 (5.00) \(\to\) Item 1 (3.33) \(\to\) Item 4 (2.40).
Step 3: Greedily load the knapsack (Capacity limit = 10 kg)
| Step | Item Picked | Weight (\(W_i\)) | Profit (\(P_i\)) | Fraction Taken | Remaining Capacity | Total Profit Accumulated |
|---|---|---|---|---|---|---|
| 1 | Item 5 | 1 kg | 8 | 1.0 (All) | \(10 - 1 = 9\) kg | 8 |
| 2 | Item 2 | 3 kg | 15 | 1.0 (All) | \(9 - 3 = 6\) kg | \(8 + 15 = 23\) |
| 3 | Item 3 | 2 kg | 10 | 1.0 (All) | \(6 - 2 = 4\) kg | \(23 + 10 = 33\) |
| 4 | Item 1 | 3 kg | 10 | 1.0 (All) | \(4 - 3 = 1\) kg | \(33 + 10 = 43\) |
| 5 | Item 4 | 5 kg | 12 | \(1/5 = 0.2\) (Fraction) | \(1 - 1 = 0\) kg | \(43 + (12 \times 0.2) = 45.4\) |
A Randomized Algorithm is an algorithm that uses random numbers to influence its decision-making logic. Instead of executing deterministically based on the input, it leverages a random source to obtain average-case behavior on worst-case inputs.
Randomized algorithms are broadly classified into two main types:
Key Advantages: They are typically simpler, faster, and require less memory than their deterministic counterparts, making them essential for cryptography, load balancing, and large data processing.
Algorithm: An algorithm is a finite, step-by-step sequence of well-defined, unambiguous instructions designed to solve a specific problem or compute a particular output from a given set of inputs.
According to Donald Knuth, any valid algorithm must satisfy these five essential characteristics:
Given matrices \(A_1(10 \times 20)\), \(A_2(20 \times 50)\), \(A_3(50 \times 1)\), and \(A_4(1 \times 100)\). The dimensions array is \(P = [10, 20, 50, 1, 100]\) for \(n = 4\) matrices. The recurrence relation is:
DP Calculation Table:
The Bellman-Ford Algorithm solves the Single Source Shortest Path problem in graphs containing negative edge weights. It runs in \(O(V \cdot E)\) time. It relaxes all edges \(|V| - 1\) times and runs a final check to detect negative-weight cycles.
Bellman-Ford(Graph G, Source S):
1. Initialize distances:
For each vertex v in G:
dist[v] = Infinity
dist[S] = 0
2. Relax all edges |V| - 1 times:
For i = 1 to |V| - 1:
For each edge (u, v) in G with weight w:
If dist[u] != Infinity and dist[u] + w < dist[v]:
dist[v] = dist[u] + w
3. Detect negative weight cycles:
For each edge (u, v) in G with weight w:
If dist[u] != Infinity and dist[u] + w < dist[v]:
Return "Graph contains a negative weight cycle!"
4. Return dist
Why \(|V| - 1\) iterations? The shortest path between any two vertices in a graph without negative cycles contains at most \(|V| - 1\) edges. Thus, relaxing all edges \(|V| - 1\) times guarantees that the shortest paths propagate throughout the graph.
Dynamic Programming (DP) is a robust paradigm, but it comes with distinct trade-offs.
Advantages:
Drawbacks:
Graph Edges: \(S \to a (1)\), \(S \to b (5)\), \(a \to c (2)\), \(a \to d (3)\), \(b \to c (2)\), \(b \to d (1)\), \(c \to e (3)\), \(d \to e (2)\), \(c \to d (5)\).
Step-by-Step Execution Trace:
| Iteration | Visited Set | dist[S] | dist[a] | dist[b] | dist[c] | dist[d] | dist[e] | Action / Relaxations |
|---|---|---|---|---|---|---|---|---|
| Init | {} | 0 | ∞ | ∞ | ∞ | ∞ | ∞ | Initialize distances. Source \(S\) is at distance 0. |
| 1 | {S} | 0 | 1 | 5 | ∞ | ∞ | ∞ | Pick min unvisited: \(S\) (0). Relax edges from \(S\): \(S \to a(1)\), \(S \to b(5)\). |
| 2 | {S, a} | 0 | 1 | 5 | 3 | 4 | ∞ | Pick min unvisited: \(a\) (1). Relax edges from \(a\): \(a \to c(1+2=3)\), \(a \to d(1+3=4)\). |
| 3 | {S, a, c} | 0 | 1 | 5 | 3 | 4 | 6 | Pick min unvisited: \(c\) (3). Relax edges from \(c\): \(c \to e(3+3=6)\). |
| 4 | {S, a, c, d} | 0 | 1 | 5 | 3 | 4 | 6 | Pick min unvisited: \(d\) (4). Relax edges from \(d\): \(d \to e\) (already 6, no change). |
| 5 | {S, a, c, d, b} | 0 | 1 | 5 | 3 | 4 | 6 | Pick min unvisited: \(b\) (5). No updates possible. |
| 6 | {S, a, c, d, b, e} | 0 | 1 | 5 | 3 | 4 | 6 | Pick min unvisited: \(e\) (6). All vertices visited. Terminate. |
Complexity theory classifies decision problems based on the computational resources needed to solve or verify them.
| Class | Full Form & Definition | Solvability (Poly-time) | Verifiability (Poly-time) | Relationship / Property | Classic Examples |
|---|---|---|---|---|---|
| P | Polynomial Time: Problems that can be solved by a deterministic Turing machine in polynomial time. | Yes | Yes | \(P \subseteq NP\). These are considered computationally tractable. | Binary Search, Merge Sort, Dijkstra's algorithm. |
| NP | Non-deterministic Polynomial Time: Decision problems where a "yes" certificate can be verified in polynomial time. | Unknown (Yes, if \(P = NP\)) | Yes | Contains \(P\) and all \(NP\)-Complete problems. | Subset Sum, Travelling Salesperson (Decision version). |
| NP-Hard | NP-Hard: Problems that are at least as hard as the hardest problems in NP. Need not be in NP. | Unknown | Unknown | Any problem in NP can be reduced to an NP-Hard problem in polynomial time. | Halting Problem (undecidable), TSP (Optimization version). |
| NP-Complete | NP-Complete: The subset of problems in NP that are also NP-Hard. They represent the hardest problems in NP. | Unknown | Yes | If any NPC problem is solved in polynomial time, then \(P = NP\). | 3-SAT, Clique, Vertex Cover, Vertex Coloring. |
This statement is a fundamental theorem of complexity theory. Let's prove it logically:
Reducibility is a formal method of transforming one problem into another. If a problem \(A\) is reducible to a problem \(B\), it means that any algorithm that solves problem \(B\) can also be used as a subroutine to solve problem \(A\).
Formally, in complexity theory, we use Polynomial-time Reduction (denoted as \(A \le_p B\)). This states that there exists a polynomial-time computable function \(f\) such that for every input instance \(x\):
Implications of Reducibility:
The code is: int fun2(int n) { if (n<=1) return n; return fun2(n-1) + fun2(n-1); }
Step 1: Formulate the Recurrence Relation
Step 2: Solve the Recurrence Relation (Expansion Method)
The recurrence relation is \(T(n) = 2T(n/2) + n\), with base case \(T(1) = c\).
We solve this using the Substitution (Expansion) Method:
The Fractional Knapsack Algorithm uses a greedy approach. Items can be broken down to fit the capacity, so we greedily select items with the highest value-to-weight ratio first.
Fractional-Knapsack(Weights[], Profits[], Capacity, n):
1. Create an array of structures or indices: Item_Ratios[]
2. For i = 0 to n-1:
Item_Ratios[i].index = i
Item_Ratios[i].ratio = Profits[i] / Weights[i]
3. Sort Item_Ratios[] in descending order of ratio values.
4. Initialize:
total_profit = 0.0
current_capacity = Capacity
5. For i = 0 to n-1:
item_idx = Item_Ratios[i].index
If Weights[item_idx] <= current_capacity:
// Take the entire item
current_capacity = current_capacity - Weights[item_idx]
total_profit = total_profit + Profits[item_idx]
Else:
// Take a fraction of the item to fill the remaining capacity
fraction = current_capacity / Weights[item_idx]
total_profit = total_profit + (Profits[item_idx] * fraction)
current_capacity = 0
Break // Knapsack is full
6. Return total_profit
Complexity: Sorting takes \(O(n \log n)\), and the selection loop takes \(O(n)\). Total time complexity is \(O(n \log n)\).
N-Queens Problem: The problem of placing \(N\) non-attacking queens on an \(N \times N\) chessboard, such that no two queens share the same row, column, or diagonal. It is solved using Backtracking by placing queens row by row and backtracking whenever a placement conflict is detected.
15-Puzzle Problem: A sliding puzzle consisting of a grid of numbered square tiles in random order with one tile missing. The grid size is \(4 \times 4\) (15 tiles, 1 empty space). The goal is to rearrange the tiles from an initial configuration to a target sorted configuration by sliding tiles into the empty space. It is solved using Branch and Bound (using heuristics like Manhattan distance in a Best-First search).
Comparison Table:
| Feature | N-Queens Problem | 15-Puzzle Problem |
|---|---|---|
| Algorithmic Paradigm | Backtracking (Constraint satisfaction) | Branch and Bound (State space optimization) |
| Search Space Traversal | Depth-First Search (DFS) | Best-First Search (using heuristics like A*) or BFS |
| Goal Requirement | Find *any* or *all* valid static configurations. | Find the *shortest path* (sequence of moves) to the goal. |
| Pruning Condition | Violating placement rules (same row, col, or diagonal). | Lower-bound cost estimate \(f(x) = g(x) + h(x)\) exceeds current minimum path cost. |
Given weights \(W = \{3, 5, 3, 4\}\), profits \(P = \{11, 7, 5, 10\}\), and capacity \(M = 15\) kg.
Step 1: Check the total weight of all items
\[\text{Total Weight} = W_1 + W_2 + W_3 + W_4 = 3 + 5 + 3 + 4 = 15 \text{ kg}\]
Step 2: Compare with Capacity
The total weight of all available items is exactly equal to the knapsack capacity (\(15 \le 15\)). Therefore, we do not need to leave any item behind. We can select all four items to achieve the maximum possible profit.
Step 3: Calculate Total Profit
\[\text{Total Profit} = P_1 + P_2 + P_3 + P_4 = 11 + 7 + 5 + 10 = 33\]
i) No, a valid shortest path cannot be determined. If a graph contains a negative weight cycle (a cycle whose sum of edge weights is less than 0) that is reachable from the source and can reach the destination, we can loop through this cycle indefinitely. Each loop decreases the total path cost. As a result, the distance between the source and destination approaches negative infinity (\(-\infty\)), making the concept of a "shortest" path mathematically undefined.
ii) The Bellman-Ford Algorithm can detect the presence of negative weight cycles. It does this by running an extra relaxation step. After relaxing all edges \(|V| - 1\) times, the algorithm attempts to relax all edges one more time (the \(|V|\)-th iteration). If any distance value updates (decreases) during this step, it indicates that a negative weight cycle exists in the graph.
To prove that the Clique Decision Problem is NP-Complete, we must complete two steps:
Step 1: Prove Clique is in NP
Step 2: Prove Clique is NP-Hard (Reduction from 3-SAT)
Given capacity \(M = 5\) kg and 4 items with weights \(W = \{2, 1, 3, 2\}\) and profits \(P = \{12, 10, 20, 15\}\).
The DP relation is: \(K[i][w] = \max(K[i-1][w], P[i] + K[i-1][w - W[i]])\) if \(W[i] \le w\), else \(K[i-1][w]\).
Step 1: Construct the DP Table
| Item (W, P) | w = 0 | w = 1 | w = 2 | w = 3 | w = 4 | w = 5 |
|---|---|---|---|---|---|---|
| 0 (None) | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 (2, 12) | 0 | 0 | 12 | 12 | 12 | 12 |
| 2 (1, 10) | 0 | 10 | 12 | 22 | 22 | 22 |
| 3 (3, 20) | 0 | 10 | 12 | 22 | 30 | 32 |
| 4 (2, 15) | 0 | 10 | 15 | 25 | 30 | 37 |
Step 2: Trace Back to Find Selected Items
Given matrices \(A_1(2 \times 3), A_2(3 \times 4), A_3(4 \times 5), A_4(5 \times 2)\). The dimensions array is \(P = [2, 3, 4, 5, 2]\) with \(n = 4\) matrices. Recurrence: \(m[i, j] = \min \{m[i, k] + m[k+1, j] + P[i-1] \cdot P[k] \cdot P[j]\}\).
Step-by-Step DP Calculations:
The Matrix Chain Order algorithm computes the minimum multiplication costs and stores the split points in an auxiliary table \(s\) to construct the optimal parenthesization.
Matrix-Chain-Order(p):
1. n = length(p) - 1
2. Create tables m[1..n, 1..n] and s[1..n-1, 2..n]
3. For i = 1 to n:
m[i, i] = 0 // Base case: cost is 0 for single matrix
4. For L = 2 to n: // L is the chain length
For i = 1 to n - L + 1:
j = i + L - 1
m[i, j] = Infinity
For k = i to j - 1:
q = m[i, k] + m[k+1, j] + p[i-1]*p[k]*p[j]
If q < m[i, j]:
m[i, j] = q
s[i, j] = k // Store split index
5. Return m and s
Complexity Analysis: The three nested loops run in \(O(n^3)\) time complexity. The space complexity is \(O(n^2)\) to store the \(m\) and \(s\) matrices.
Circuit Satisfiability (Circuit-SAT) Problem: Given a combinatorial boolean circuit containing input wires, logic gates (AND, OR, NOT), and a single output wire, the problem is to determine if there exists an assignment of truth values to the inputs that makes the final output wire TRUE (1).
Proof that Circuit-SAT is in NP:
The state-space tree shows the step-by-step placement of queens in rows 1, 2, 3, and 4. Backtracking prunes paths immediately when a conflict occurs. Below is the detailed tree, where \(Q(r, c)\) represents a queen placed at row \(r\), column \(c\), and (X) denotes pruning due to conflicts.
Root (Start)
/ | \ \
Q(1,1) Q(1,2) Q(1,3) Q(1,4)
/ \ / \ / \ / \
Q(2,3) Q(2,4) Q(2,4) Q(2,1)-(X) Q(2,1) Q(2,2)-(X) Q(2,1) Q(2,2)-(X)
/ \ / / \ / \ / \
Q(3,X) Q(3,2) Q(3,1) Q(3,3)-(X) Q(3,4) Q(3,2)-(X) Q(3,3) Q(3,X)
(X) / / / /
Q(4,X) Q(4,3) Q(4,2) Q(4,X)
(X) [SOLUTION 1: 2-4-1-3] [SOLUTION 2: 3-1-4-2] (X)
Col placements: Col placements:
Row 1 -> Col 2 Row 1 -> Col 3
Row 2 -> Col 4 Row 2 -> Col 1
Row 3 -> Col 1 Row 3 -> Col 4
Row 4 -> Col 3 Row 4 -> Col 2
This state-space tree visualizes how backtracking searches depth-first and prunes subtrees to arrive at the two valid solutions for the 4-Queens problem.
We solve this using the Greedy Activity Selection method.
Step 1: Sort activities by finish times (ascending order)
The input activities are already sorted by finish times.
Step 2: Greedily pick compatible activities
We solve the All-Pairs Shortest Path problem using the Floyd-Warshall Algorithm.
Step 1: Construct Initial Distance Matrix \(D^{(0)}\)
\[D^{(0)} = \begin{pmatrix} 0 & -5 & 2 & \infty \\ \infty & 0 & 4 & \infty \\ \infty & \infty & 0 & 1 \\ 3 & 2 & \infty & 0 \end{pmatrix}\]
Step 2: Compute \(D^{(1)}\) (Intermediate vertex \(k = 0\))
We check if we can shorten paths using node 0: \(D^{(1)}[i][j] = \min(D^{(0)}[i][j], D^{(0)}[i][0] + D^{(0)}[0][j])\).
\[D^{(1)} = \begin{pmatrix} 0 & -5 & 2 & \infty \\ \infty & 0 & 4 & \infty \\ \infty & \infty & 0 & 1 \\ 3 & -2 & 5 & 0 \end{pmatrix}\]
Step 3: Compute \(D^{(2)}\) (Intermediate vertex \(k = 1\))
Check paths via node 1: \(D^{(2)}[i][j] = \min(D^{(1)}[i][j], D^{(1)}[i][1] + D^{(1)}[1][j])\).
\[D^{(2)} = \begin{pmatrix} 0 & -5 & -1 & \infty \\ \infty & 0 & 4 & \infty \\ \infty & \infty & 0 & 1 \\ 3 & -2 & 2 & 0 \end{pmatrix}\]
Step 4: Compute \(D^{(3)}\) (Intermediate vertex \(k = 2\))
Check paths via node 2: \(D^{(3)}[i][j] = \min(D^{(2)}[i][j], D^{(2)}[i][2] + D^{(2)}[2][j])\).
\[D^{(3)} = \begin{pmatrix} 0 & -5 & -1 & 0 \\ \infty & 0 & 4 & 5 \\ \infty & \infty & 0 & 1 \\ 3 & -2 & 2 & 0 \end{pmatrix}\]
Step 5: Compute \(D^{(4)}\) (Intermediate vertex \(k = 3\))
Check paths via node 3: \(D^{(4)}[i][j] = \min(D^{(3)}[i][j], D^{(3)}[i][3] + D^{(3)}[3][j])\).
\[D^{(4)} = \begin{pmatrix} 0 & -5 & -1 & 0 \\ 8 & 0 & 4 & 5 \\ 4 & -1 & 0 & 1 \\ 3 & -2 & 2 & 0 \end{pmatrix}\]
All values on the main diagonal are 0, verifying that there are no negative weight cycles. This is the final shortest paths matrix.