Algorithm
Algorithm
DESIGN OF
ALGORITHMS
(BCS401)
2025
_______________________________________________________________________________________________
TITLE :
MODULE 1 :
MODULE 2 :
MODULE 3 :
MODULE 4 :
MODULE 5 :
QUESTION PAPERS :
Q1 :
Q2 :
Q3 :
Q4 :
Q5 :
Q6 :
Q7 :
_________________________________________
Lecture Notes on
Analysis and Design of Algorithms
BCS401
Contents
1. Introduction
1.1. What is an Algorithm?
1.2. Algorithm Specification
1.3. Analysis Framework
2. Performance Analysis
2.1. Space complexity
2.2. Time complexity
3. Asymptotic Notations
3.1. Big-Oh notation
3.2. Omega notation
3.3. Theta notation
3.4. Little-oh notation
3.5. Basic symptotic notations
3.6. Mathematical analysis of Recursive and non-recursive algorithm
4. Brute force design technique:
4.1. Selection sort
4.2. Sequential search
4.3. String matching algorithm with complexity Analysis.
1
ADA BCS401
Module-1: Introduction
1.1 Introduction
1.1.1 What is an Algorithm?
Algorithm: An algorithm is a finite sequence of unambiguous instructions to solve a particular
problem.
Example: In C++ the same algorithm can be specified as follows. Here Type is a basic or user
defined data type.
CSE, SVIT 1
2
ADA BCS401
CSE, SVIT 2
3
ADA BCS401
Orders of Growth
Why this emphasis on the count's order of growth for large input sizes? Because for large values of n, it
is the function's order of growth that counts: just look at table which contains values of a few functions
particularly important for analysis of algorithms.
Table: Values of several functions important for analysis of algorithms
Algorithms that require an exponential number of operations are practical for solving only problems of
very small sizes.
Here fixed component depends on the size of a, b and c. Also instance characteristics Sp=0
CSE, SVIT 3
4
ADA BCS401
Example-2: Let us consider the algorithm to find sum of array. For the algorithm given here the
problem instances are characterized by n, the number of elements to be summed. The space needed by
a[ ]depends on n.So the space complexity can be written as;Ssum(n) ≥ (n+3); n for a[ ], One each for
n, i and s.
Method-2: Determine the step count of an algorithm by building a table in which we list the total
number of steps contributed by each statement. An example is shown below. The code will find the sum
of n numbers.
Example: Matrix addition
CSE, SVIT 4
5
ADA BCS401
The above method is both excessively difficult and, usually unnecessary. The thing to do is to identify the most
important operation contributing the m operation of the algorithm, called the basic operation, the st to the total
running time, and compute the number of times the basic operation is executed.
Trade-off
There is often a time-space-tradeoff involved in a problem, that is, it cannot be solved with few
computing time and low memory consumption. One has to make a compromise and to exchange
computing time for memory consumption or vice versa, depending on which algorithm one chooses
and how one parameterizes it.
Informally, O(g(n)) is the set of all functions with a lower or same order of growth as g(n). Note
that the definition gives us a lot of freedom in choosing specific valuesfor constants c and n0.
CSE, SVIT 5
6
ADA BCS401
Strategies to prove Big-O: Sometimes the easiest way to prove that f (n) = O(g(n)) is to take c to
be the sum of the positive coefficients off(n). We can usually ignore the negative coefficients.
Here is an example of the formal proof that n3 ∈Ω(n2):n3 ≥ n2 for all n ≥ 0, i.e., we
can select c = 1 and n0 = 0.
Example:
7
ADA BCS401
CSE, SVIT 7
8
ADA BCS401
Example: n2 + 5n + 7 = Θ(n2)
CSE, SVIT 8
9
ADA BCS401
Theorem: If t1(n) ∈O(g1(n)) and t2(n) ∈O(g2(n)), then t1(n) + t2(n) ∈O(max{g1(n), g2(n)}). (The
analogous assertions are true for the Ω and Ө notations as well.)
Proof: The proof extends to orders of growth the following simple fact aboutfour arbitrary real numbers
a1, b1, a2, b2: if a1 ≤ b1 and a2 ≤ b2, then a1 + a2 ≤ 2 max{b1, b2}.
Since t1(n) ∈O(g1(n)), there exist some positive constant c1 and some nonnegative integer n1 such that
t1(n) ≤ c1g1(n) for all n ≥ n1.
Similarly, since t2(n) ∈O(g2(n)), t2(n) ≤ c2g2(n) for all n ≥ n2.
Let us denote c3 = max{c1, c2} and consider n>=max{n1,n2} so that
we can use both inequalities. Adding them yields the following: t1(n) + t2(n) ≤ c1g1(n) + c2g2(n)
≤ c3 g1(n) + c3g2(n) = c3[g1(n) + g2(n)]
3.4. Little Oh The function f(n)= o(g(n)) [ i.e f of n is a little oh of g of n ] if and only if
lim ƒ(𝑛) = 0
𝑛→∞ 𝑔(𝑛)
Example:
CSE, SVIT 9
10
ADA BCS401
CSE, SVIT 10
11
ADA BCS401
Here comparison is the basic operation. Note that number of comparisions will be same for all
arrays of size n. Therefore, no need to distinguish worst, best and average cases. Total number of
basic operations are,
Example-2: To check whether all the elements in the given array are distinct
CSE, SVIT 11
12
ADA BCS401
Here basic operation is comparison. The maximum no. of comparisons happens in the worst case. i.e.
all the elements in the array are distinct and algorithms return true).
Total number of basic operations (comparison) in the worst case are,
Other than the worst case, the total comparisons areless than 1 𝑛2. For example if the first two elements
2
of the array are equal, only one comparison is computed. So in general C(n) =O(n2)
CSE, SVIT 12
13
ADA BCS401
Example-1
14
ADA BCS401
Condition that makes the algorithm stopif n = 0 return 1. Thus recurrence relation and initial
conditionfor the algorithm’s number of multiplications M(n) can be stated as
….
Example-2: Tower of Hanoi puzzle. In this puzzle, There are n disks of different sizes that canslide
onto any of three pegs. Initially, all the disks are on the first peg in order ofsize, the largest on the bottom
and the smallest on top. The goal is to move all thedisks to the third peg, using the second one as an
auxiliary, if necessary. We canmove only one disk at a time, and it is forbidden to place a larger disk on
top of asmaller one.The problem has an elegant recursive solution, which is illustrated in Figure.
1. If n = 1, we move the single disk directly from the source peg to the destination peg.
2. To move n>1 disks from peg 1 to peg 3 (with peg 2 as auxiliary),
o we first move recursively n-1 disks from peg 1 to peg 2 (with peg 3 as auxiliary),
o then move the largest disk directly from peg 1 to peg 3, and,
o finally, move recursively n-1 disks from peg 2 to peg 3 (using peg 1 as auxiliary).
CSE, SVIT 14
15
ADA BCS401
We have the following recurrence relation for the number of moves M(n):
The pattern of the first three sums on the left suggests that the next one will be
Since the initial condition is specified for n = 1, which is achieved for i = n-1, we get the
following formula for the solution to recurrence,
The standard approach to solving such a recurrence is to solve it only for n = 2k and then take
advantage of the theorem called the smoothness rule which claims that under very broad
CSE, SVIT 15
16
ADA BCS401
assumptions the order of growth observed for n = 2k gives a correct answer about the order of
growth for all values of n.
CSE, SVIT 16
17
ADA BCS401
We start selection sort by scanning the entire given list to find its smallest element and exchange it with
the first element, putting the smallest element in its final position in the sorted list. Then we scan the list, starting
with the second element, putting the second smallest element in its final position. Generally, on the ith pass
through the list, which we number from 0 to n-2, the algorithm searches for the last n-I elements and swaps it with
Ai:
The number of times the algorithm executed depends only on the array’s size and is given by
This is also called as Linear search. Here we start from the initial element of the array and compare it with the
search key. We repeat the same with all the elements of the array till we encounter the search key or till we reach
end of the array.
CSE, SVIT 17
18
ADA BCS401
The time efficiency in worst case is O(n), where n is the number of elements of the array. In best case it is O(1), it
means the very first element is the search key.
Another example of Brute force approach is string matching, where string of n characters called text and a string
of m characters (m<=n) called the pattern is given. Here job is to find whether the pattern is present in text or not.
If we want to find i-the index of the leftmost character of the first matching substring in the
We start matching with the very first character, if a match then only j is incremented and again compared with next
character of both the strings. If not then I is incremented and j starts from beginning of pattern string. If pattern
found we return the position from where the pattern began. Pattern is tried to match till n-m elements, later we
need not try to match as the elements will be lesser than pattern. If it doesn’t match by n-m elements then pattern is
not matched.
CSE, SVIT 18
19
Lecture Notes on
Analysis and Design of Algorithms
BCS401
Contents
1. General method
2. Recurrence equation
3. Algorithm: Binary search
4. Algorithm: Finding the maximum and minimum
5. Algorithm: Merge sort
6. Algorithm: Quick sort
7. Advantages and Disadvantages
8. Decrease and Conquer Approach
9. Algorithm: Topological Sort
20
ADA BCS401
1. General method
Divide and Conquer is one of the best-known general algorithm design echnique. It works
according to the following general plan:
Given a function to compute on ‘n’ inputs the divide-and-conquer strategy suggests
splitting the inputs into ‘k’ distinct subsets, 1<k<=n, yielding ‘k’ sub problems.
These sub problems must be solved, and then a method must be found to combine sub
solutions into a solution of the whole.
If the sub problems are still relatively large, then the divide-and-conquer strategy can
possibly be reapplied.
Often the sub problems resulting from a divide-and-conquer design are of the same
type as the original problem.For those cases the reapplication of the divide-and-
conquer principle is naturally expressed by a recursive algorithm.
Problem of size n
CSE, SVIT 1
21
ADA BCS401
Where,
T(n) is the time for divide and conquer method on any input of size n and
g(n) is the time to compute answer directly for small inputs.
The function f(n) is the time for dividing the problem ‘p’ and combining the solutions
to sub problems.
For divide and conquer based algorithms that produce sub problems of the same type as the
original problem, it is very natural to first describe them by using recursion.
More generally, an instance of size n can be divided into b instances of size n/b, with a of
them needing to be solved. (Here, a and b are constants; a>=1 and b > 1.). Assuming that
size n is a power of b(i.e. n=bk), to simplify our analysis, we get the following recurrence for
the running time T(n):
..... (1)
where f(n) is a function that accounts for the time spent on dividing the problem into smaller
ones and on combining their solutions.
The recurrence relation can be solved by i) substitution method or by using ii) master
theorem.
1. Substitution Method - This method repeatedly makes substitution for each
occurrence of the function T in the right-hand side until all such occurrences
disappear.
2. Master Theorem - The efficiency analysis of many divide-and-conquer algorithms is
greatly simplified by the master theorem. It states that, in recurrence equation T(n) =
aT(n/b) + f (n), If f (n)∈ Θ (nd) where d ≥ 0 then
CSE, SVIT 2
22
ADA BCS401
Problems on Substitution method & Master theorem to solve the recurrence relation
CSE, SVIT 3
23
ADA BCS401
CSE, SVIT 4
24
ADA BCS401
CSE, SVIT 5
25
ADA BCS401
CSE, SVIT 6
26
ADA BCS401
3. Binary Search
Problem definition:Let ai, 1 ≤ i ≤ n be a list of elements that are sorted in non-decreasing
order. The problem is tofind whether a given element x is present in the list or not. If x is
present we have to determine a value j (element’s position) such that aj=x. If x is not in the
list, then j is set to zero.
Solution:Let P = (n, ai…al , x) denote an arbitrary instance of search problem where n is the
number of elements in the list, ai…alis the list of elements andx is the key element to be
searched for in the given list.Binary search on the list is done as follows:
Step1: Pick an index q in the middle range [i, l] i.e. q= (𝑛 + 1)/2] and compare x with aq.
Step 2: if x = aqi.e key element is equal to mid element, the problem is immediately solved.
Step 3: if x <aqin this case x has to be searched for only in the sub-list ai, ai+1, ……, aq-
Therefore, problem reduces to (q-i, ai…aq-1, x).
Step 4: if x >aq,x has to be searched for only in the sub-list aq+1, ...,., al . Therefore problem
reduces to (l-i, aq+1…al, x).
For the above solution procedure, the Algorithm can be implemented as recursive or non-
recursive algorithm.
CSE, SVIT 7
27
ADA BCS401
CSE, SVIT 8
28
ADA BCS401
Analysis
In binary search the basic operation is key comparison. Binary Search can be analyzed with
the best, worst, and average case number of comparisons.The numbers of comparisons for the
recursive and iterative versions of Binary Search are the same, if comparison counting is
relaxed slightly. For Recursive Binary Search, count each pass through the if-then-else block
as one comparison. For Iterative Binary Search, count each pass through the while block as
one comparison.Let us find out how many such key comparison does the algorithm make on
an array of n elements.
Best case –Θ(1) In the best case, the key is the middle in the array. A constant number of
comparisons (actually just 1) are required.
Worst case - Θ(log2 n) In the worst case, the key does not exist in the array at all. Through
each recursion or iteration of Binary Search, the size of the admissible range is halved. This
halving can be done ceiling(log2n ) times. Thus, ] log2 n ] comparisons are required.
Sometimes, in case of the successful search, it may take maximum number of comparisons.
] log2 n ]. So worst case complexity of successful binary search is Θ (log2 n).
Average case - Θ (log2n) To find the average case, take the sum of the product of number of
comparisons required to find each element and the probability of searching for that element.
To simplify the analysis, assume that no item which is not in array will be searched for, and
that the probabilities of searching for each element are uniform.
Space Complexity - The space requirements for the recursive and iterative versions of binary
search are different. Iterative Binary Search requires only a constant amount of space, while
Recursive Binary Search requires space proportional to the number of comparisons to
maintain the recursion stack.
Advantages: Efficient on very big list, Can be implemented iteratively/recursively.
Limitations:
Interacts poorly with the memory hierarchy
Requires sorted list as an input
Due to random access of list element, needs arrays instead of linked list.
CSE, SVIT 9
29
ADA BCS401
Explanation:
StraightMaxMin requires 2(n-1) comparisons in the best, average & worst cases.
By realizing the comparison of a[i]>max is false, improvement in a algorithm can be
done. Hence we can replace the contents of the for loop by,
If(a[i]>Max) then Max = a[i]; Else if (a[i]<min) min=a[i]
On the average a[i] is > max half the time.So, the avg. no. of comparison is 3n/2-1.
CSE, SVIT 10
30
ADA BCS401
Example:
CSE, SVIT 11
31
ADA BCS401
Compared with the straight forward method (2n-2) this method saves 25% in comparisons.
Space Complexity
Compared to the straight forward method, the MaxMin method requires extra stack space for
i, j, max, min, max1 and min1. Given n elements there will be 𝑙o𝑔2𝑛] + 1 levels of
recursion and we need to save seven values for each recursive call. (6 + 1 for return address).
5. Merge Sort
Merge sort is a perfect example of a successful application of the divide-and conquer
technique. It sorts a given array A [O ... n - 1] by dividing it into two halves A [0 .. 𝑛/2]-1]
and A [ /2] .. n-1], sorting each of them recursively, and then merging the two smaller sorted
arrays into a single sorted one.
CSE, SVIT 12
32
ADA BCS401
After that, the index of the smaller element is incremented to point to its immediate
successor in the array it was copied from. This operation is repeated until one of the
two given arrays is exhausted, and then the remaining elements of the other array are
copied to the end of the new array.
Example:
The operation of the algorithm on the
list 8, 3, 2, 9, 7, 1, 5, 4 is illustrated in
the figure
Analysis
Here the basic operationis key comparison. As merge sort execution does not depend on the
order of the data, best case and average case runtime are the same as worst case runtime.
Worst case:During key comparison, neither of the two arrays becomes empty before the
other one contains just one element leads to the worst case of merge sort. Assuming for
CSE, SVIT 13
33
ADA BCS401
simplicity that total number of elementsn is a power of 2, therecurrence relation for the
number of key comparisons C(n) is
where, Cmerge(n) is the number of key comparisons made during the merging stage.
Let us analyze Cmerge(n), the number of key comparisons performed during themerging stage.
At each step, exactly one comparison is made, after which the totalnumber of elements in the
two arrays still needing to be processed is reducedby 1. In the worst case, neither of the two
arrays becomes empty before theother one contains just one element (e.g., smaller elements
may come from thealternating arrays).Therefore, for the worst case,Cmerge(n) = n –1.
Now,
Advantages:
Number of comparisons performed is nearly optimal.
For large n, the num er of comparisons made by this algorithm in the average case
turns out to be about 0.25n less and hence is also in Θ(n log n).
Mergesort will never degrade to O (n2)
Anotheradvantage of mergesort over quicksort and heapsort is its stability. (A sorting
algorithm is said to be stable if two objects with equal keys appear in the same order
in sorted output as they appear in the input array to be sorted. )
Limitations:
The principal shortcoming of mergesort is the linear amount [O(n) ] of extra storage
the algorithm requires. Though merging can be done in-place, the resulting algorithm
is quite complicated and of theoretical interest only.
CSE, SVIT 14
34
ADA BCS401
6. Quick sort
Quicksort is the other important sorting algorithm that is based on the divide-and-conquer
approach. Unlike mergesort, which divides its input elements according to their position in
the array, quicksort divides ( or partitions) them according to their value.
A partition is an arrangement of the array’s elements so that all the elements to the left of
some element A[s] are less than or equal to A[s], and all the elements to the right of A[s] are
greater than or equal to it:
Obviously, after a partition is achieved, A[s] will be in its final position in thesorted array,
and we can continue sorting the two subarrays to the left and to theright of A[s]
independently (e.g., by the same method).
In quick sort, the entire workhappens in the division stage, with no work required to combine
the solutions tothe subproblems.
Partitioning
We start by selecting a pivot—an element with respect to whose valuewe are going to divide
the subarray.There are several different strategies forselecting a pivot. We use
thesophisticated method suggested byC.A.R. Hoare, the prominent British computer scientist
who invented quicksort.
Select the subarray’s firstelement: p = A[l].Now scan the subarray from both ends,comparing
the subarray’s elements to the pivot.
The left-to-right scan, denoted below by index pointer i, starts with the second
element. Since we want elements smaller than the pivot to be in the left part of the
subarray, this scan skips over elements that are smaller than the pivot and stops upon
encountering the first element greater than or equal to the pivot.
The right-to-left scan, denoted below by index pointer j, starts with the last element of
the subarray. Since we want elements larger than the pivot to be in the right part of the
CSE, SVIT 15
35
ADA BCS401
subarray, this scan skips over elements that are larger than the pivot and stops on
encountering the first element smaller than or equal to the pivot.
After both scans stop, three situations may arise, depending on whether or notthe scanning
indices have crossed.
1. If scanning indices i and j have not crossed, i.e., i< j, we simply exchange A[i] and
A[j ] and resume the scans by incrementing I and decrementing j, respectively:
2. If the scanning indices have crossed over, i.e., i> j, we will have partitioned the
subarray after exchanging the pivot with A[j]:
3. If the scanning indices stop while pointing to the same element, i.e., i = j, the value
they are pointing to must be equal to p. Thus, we have the subarray partitioned, with
the split position s = i = j :
We can combine this with the case-2 byexchanging the pivot with A[j] whenever i≥j
ALGORITHM HoarePartition(A[l..r])
//Partitions a subarray by Hoare’s algorithm, using the first element as a pivot
//Input: Subarray of array A[0..n − 1], defined by its left and right indices l and r (l<r)
//Output: Partition of A[l..r], with the split position returned as this function’s value
Note that index i can go out of the subarray’s bounds in this pseudocode.
CSE, SVIT 16
36
ADA BCS401
Analysis
Best Case -Here the basic operation is key comparison. Numberof key comparisons made
before a partition is achieved is n + 1 if the scanningindices cross over and n if they coincide.
If all the splits happen in themiddle of corresponding subarrays, we will have the best case.
The number of keycomparisons in the best case satisfies the recurrence,
According to the Master Theorem, Cbest(n) ∈Θ(n log2 n); solving it exactly forn = 2k yields
Cbest(n) = n log2 n.
Worst Case – In the worst case, all the splits will be skewed to the extreme: one of thetwo
subarrays will be empty, and the size of the other will be just 1 less than thesize of the
subarray being partitioned. This unfortunate situation will happen, inparticular, for increasing
arrays. Indeed, if A[0..n − 1] is a strictly increasing array and we use A[0] as thepivot, the
CSE, SVIT 17
37
ADA BCS401
left-to-right scan will stop on A[1] while the right-to-left scan will go allthe way to reach
A[0], indicating the split at position 0:So, after making n + 1 comparisons to get to this
partition and exchanging thepivot A[0] with itself, the algorithm will be left with the strictly
increasing arrayA[1..n − 1] to sort. This sorting of strictly increasing arrays of diminishing
sizes willcontinue until the last one A[n−2.. n−1] has been processed. The total numberof key
comparisons made will be equal to
Average Case - Let Cavg(n) be the average number of key comparisons made byquicksort on
a randomly ordered array of size n. A partition can happen in anyposition s (0 ≤ s ≤ n−1) after
n+1comparisons are made to achieve the partition.After the partition, the left and right
subarrays will have s and n − 1− s elements,respectively. Assuming that the partition split can
happen in each position s withthe same probability 1/n, we get the following recurrence
relation:
Its solution, which is much trickier than the worst- and best-case analyses, turnsout to be
Thus, on the average, quicksort makes only 39% more comparisons than in thebest case.
Moreover, its innermost loop is so efficient that it usually runs faster thanmergesort on
randomly ordered arrays of nontrivial sizes. This certainly justifies the namegiven to the
algorithm by its inventor.
Variations: Because of quicksort’s importance, there have been persistent efforts over
theyears to refine the basic algorithm. Among several improvements discovered
byresearchers are:
Better pivot selection methods such as randomized quicksort that uses a random
element or the median-of-three method that uses the median of the leftmost,
rightmost, and the middle element of the array
Switching to insertion sort on very small subarrays (between 5 and 15 elements for
most computer systems) or not sorting small subarrays at all and finishing the
algorithm with insertion sort applied to the entire nearly sorted array
Modifications of the partitioning algorithm such as the three-way partition into
segments smaller than, equal to, and larger than the pivot
Limitations: 1. It is not stable. 2. It requires a stack to store parameters of subarrays that are
yet to be sorted. 3. WhilePerformance on randomly ordered arrays is known to be sensitive
not only to the implementation details of the algorithm but also to both computer architecture
and data type.
CSE, SVIT 18
38
ADA BCS401
CSE, SVIT 19
39
ADA BCS401
Figure: Decrease-(byhalf)-and-conquer
technique.
Example:
CSE, SVIT 20
40
Insertion sort
It is an application for decease-by-one technique to sort an array A[0…n-1]. Everytime the element is
inserted, it is stored in its position. So after every insertion the array remains sorted.
41
9. Topological Sort
Background: A directed graph, or digraph for short, is a graph with directions specified for
all its edges. The adjacency matrix and adjacency lists are the two principal means of
representing a digraph.Ther are only two notable differences between undirected and
directed graphs in representing them: (1) the adjacency matrix of a directed graph does not
have to be symmetric; (2) an edge in a directed graph has just one (not wo) corresponding
nodes in the digraph’s adjacency lists.
Depth-first search and breadth-first search are principal traversal algorithms for traversing
digraphs as well, but the structure of corresponding forests can be more complex than for
undirected graphs. Thus, even for the simple example of Figure, the depth-first search forest
(Figure b) exhibits all four types of edges possible in a DFS forest of a directed graph:
tree edges (ab, bc, de),
back edges (ba) from vertices to their ancestors,
forward edges (ac) from vertices to their descendants in the tree other than their
children, and
cross edges (dc), whichare none of the aforementioned types.
Note that a back edge in a DFS forest of a directed graph can connect a vertexto its parent.
Whether or not it is the case, the presence of a back edge indicatesthat the digraph has a
directed cycle. A directed cycle in a digraph is a sequenceof three or more of its vertices that
starts and ends with the same vertex and inwhich every vertex is connected to its immediate
predecessor by an edge directedfrom the predecessor to the successor. For example, a, b, a is
a directed cycle in the digraph in Figure given above. Conversely, if a DFS forest of a
digraph has no backedges, the digraph is a dag, an acronym for directed acyclic graph.
42
ADA BCS401
courses?The situation can be modeled by a digraph in which vertices represent courses and
directed edges indicate prerequisite requirements.
In terms of this digraph, the uestion is whether we can list its vertices in such an order that
for every edge in the graph, the vertex where the edge starts is listed before the vertex where
the edge ends. In other words, can you find such an ordering of this digraph’s vertices? This
problem is called topological sorting.
Topological Sort: For topological sorting to be possible, a digraph in question must be a
DAG. i.e., if a digraph has nodirected cycles, the topological sorting problem for it has a
solution.
There are two efficient algorithms that both verify whether a digraph is a dag and, if it is,
produce an ordering of vertices that solves the topological sortingproblem.The first one is
based on depth-first search; the second is based on a direct application of the decrease-by-one
technique.
Topological Sorting based on DFS
Method
1. Perform a DFS traversal and note the order in which vertices become dead-ends
2. Reversing this order yields a solution to the topological sorting problem, provided, of
course, no back edge has been encountered during the traversal. If a back edge has
been encountered, the digraph is not a DAG, and topological sorting of its vertices is
impossible.
Illustration
a) Digraph for which the topological sorting problem needs to be solved.
b) DFS traversal stack w th the subscript numbers indicating the popping off order.
c) Solution to the problem. Here we have drawn the edges of the digraph, and they all
point from left to right as the problem’s statement requires. It is a convenient way to
check visually the correctness of a solution to an instance of the topological sorting
problem.
CSE, SVIT 23
43
ADA BCS401
Note: The solution obtained by the source-removal algorithm is different from the one
obtained by the DFS-based algorithm. Both of them are correct, of course; the topological
sorting problem may have several alternative solutions.
Depth first search:
CSE, SVIT 24
44
Breadth first search:
45
46
Applications of Topological Sorting
Instruction scheduling in program compilation
Cell evaluation ordering in spreadsheet formulas,
Resolving symbol dependencies in linkers.
***
47
Lecture Notes on
Analysis and Design of Algorithms
BCS401
Contents
48
ADA BCS401
CSE, SVIT 1
49
ADA BCS401
Solution for coin change problem using greedy algorithm is very intuitive and called as
cashier’s algorithm. Basic principle is: At every iteration for search of a coin, take the
largest coin which can fit into remain amount to be changed at that particular time. At
the end you will have optimal solution.
There are several greedy methods to obtain the feasible solutions. Three are discussed here
a) At each step fill the knapsack with the object with largest profit - If the object under
consideration does not fit, then the fraction of it is included to fill the knapsack. This method
does not result optimal solution. As per this method the solution to the above problem is as
follows;
Select Item-1 with profit p1=25, here w1=18, x1=1. Remaining capacity = 20-18 = 2
Select Item-2 with profit p1=24, here w2=15, x1=2/15. Remaining capacity = 0
Total profit earned = 28.2.
Therefore optimal solution is (x1, x2, x3) = (1, 2/15, 0) with profit = 28.2
b) At each step fill the object with smallest weight
Select Item-3 with profit p1=15, here w1=10, x3=1. Remaining capacity = 20-10 = 10
Select Item-2 with profit p1=24, here w2=15, x1=10/15. Remaining capacity = 0
Total profit earned = 31.
Optimal solution using this method is (x1, x2, x3) = (0, 2/3, 1) with profit = 31
Note: Optimal solution is not guaranteed using method a and b
CSE, SVIT 2
50
ADA BCS401
Analysis:
Disregarding the time to initially sort the object, each of the above strategies use O(n) time,
Note: The greedy approach to solve 0/1 knapsack problem does not necessarily yield an optimal
solution
CSE, SVIT 3
51
ADA BCS401
The greedy strategy to solve job sequencing problem is, “At each time select the job that that
satisfies the constraints and gives maximum profit. i.e consider the jobs in the non-increasing
order of the pi’s”
By following this procedure, we get the 3rd solution in the example 4.3. It can be proved that,
this greedy strategy always results optimal solution
CSE, SVIT 4
52
ADA BCS401
Algorithm/Program 4.6: Greedy algorithm for sequencing unit time jobs with deadlines and
profits
Analysis:
CSE, SVIT 5
53
ADA BCS401
CSE, SVIT 6
54
ADA BCS401
Problem: Find solution generated by job sequencing problem with deadlines for 7 jobs given
profits 3, 5, 20, 18, 1, 6, 30 and deadlines 1, 3, 4, 3, 2, 1, 2 respectively.
Solution: Given
J1 J2 J3 J4 J5 J6 J7
Profit 3 5 20 18 1 6 30
Deadline 1 3 4 3 2 1 2
Sort the jobs as per the decreasing order of profit
J7 J3 J4 J6 J2 J1 J5
Profit 30 20 18 6 5 3 1
Deadline 2 4 3 1 3 1 2
Maximum deadline is 4. Therefore create 4 slots. Now allocate jobs to highest slot, starting
from the job of highest profit
Select Job 7 – Allocate to slot-2 Slot 1 2 3 4
Select Job 3 – Allocate to slot-4 Job J6 J7 J 4 J3
Select Job 4 – Allocate to slot-3
Select Job 6 – Allocate to slot-1 Total profit earned is = 30+20+18+6=74
Problem: What is the solution generated by job sequencing when n = 5, (P1, P2, P3, P4, P5)
= (20, 15, 10, 5, 1), (d1, d2, d3, d4, d5) = (2, 2, 1, 3, 3)
Solution
The Jobs are already sorted according to decreasing order of profit.
Maximum deadline is 3. Therefore create 4 slots. Allocate jobs to highest slot, starting from
the job of highest profit
Select Job 1 – Allocate to slot-2
Select Job 2 – Allocate to slot-1 as 2 is already filled Slot 1 2 3
Job J2 J1 J4
Select Job 3 –Slot-2 &1 are already filled. Cannot be allocated.
Select Job 4 – Allocate to slot-3
Total profit earned is = 20+15+5=40
CSE, SVIT 7
55
ADA BCS401
CSE, SVIT 8
56
ADA BCS401
Analysis of Efficiency
The efficiency of Prim’s algorithm depends on the data structures chosen for the graph itself
and for the priority queue of the set V − VT whose vertex priorities are the distances to the
nearest tree vertices.
1. If a graph is represented by its weight matrix and the priority queue is implemented as
an unordered array, the algorithm’s running time will be in Θ(|V|2). Indeed, on each
CSE, SVIT 9
57
ADA BCS401
of the |V| − 1iterations, the array implementing the priority queue is traversed to find
and delete the minimum and then to update, if necessary, the priorities of the remaining
vertices.
We can implement the priority queue as a min-heap. (A min-heap is a complete binary tree in
which every element is less than or equal to its children.) Deletion of the smallest element from
and insertion of a new element into a min-heap of size n are O(log n) operations.
2. If a graph is represented by its adjacency lists and the priority queue is implemented
as a min-heap, the running time of the algorithm is in O(|E| log |V |).
This is because the algorithm performs |V| − 1 deletions of the smallest element and makes |E|
verifications and, possibly, changes of an element’s priority in a min-heap of size not exceeding
|V|. Each of these operations, as noted earlier, is a O(log |V|) operation. Hence, the running
time of this implementation of Prim’s algorithm is in
(|V| − 1+ |E|) O (log |V |) = O(|E| log |V |) because, in a connected graph, |V| − 1≤ |E|.
CSE, SVIT 10
58
ADA BCS401
The fact that ET ,the set of edges composing a minimum spanning tree of graph G actually a
tree in Prim's algorithm but generally just an acyclic sub graph in Kruskal's algorithm.
Kruskal’s algorithm is not simpler because it has to check whether the addition of the next
edge to the edges already selected would create a cycle.
Analysis of Efficiency
The crucial check whether two vertices belong to the same tree can be found out using union-
find algorithms.
Efficiency of Kruskal’s algorithm is based on the time needed for sorting the edge weights of
a given graph. Hence, with an efficient sorting algorithm, the time efficiency of Kruskal's
algorithm will be in O (|E| log |E|).
Illustration
An example of Kruskal’s algorithm is shown below. The
selected edges are shown in bold.
CSE, SVIT 11
59
ADA BCS401
CSE, SVIT 12
60
ADA BCS401
set of vertices adjacent to the vertices in Ti can be referred to as "fringe vertices"; they
are the candidates from which Dijkstra's algorithm selects the next vertex nearest to the
source.
To identify the ith nearest vertex, the algorithm computes, for every fringe vertex u, the
sum of the distance to the nearest tree vertex v (given by the weight of the edge (v, u))
and the length d., of the shortest path from the source to v (previously determined by
the algorithm) and then selects the vertex with the smallest such sum. The fact that it
suffices to compare the lengths of such special paths is the central insight of Dijkstra's
algorithm.
To facilitate the algorithm's operations, we label each vertex with two labels.
o The numeric label d indicates the length of the shortest path from the source to this
vertex found by the algorithm so far; when a vertex is added to the tree, d indicates
the length of the shortest path from the source to that vertex.
o The other label indicates the name of the next-to-last vertex on such a path, i.e.,
the parent of the vertex in the tree being constructed. (It can be left unspecified for
the sources and vertices that are adjacent to none of the current tree vertices.)
With such labeling, finding the next nearest vertex u* becomes a simple task of finding
a fringe vertex with the smallest d value. Ties can be broken arbitrarily.
After we have identified a vertex u* to be added to the tree, we need to perform two
operations:
o Move u* from the fringe to the set of tree vertices.
o For each remaining fringe vertex u that is connected to u* by an edge of weight
w(u*, u) such that du*+ w(u*, u) <du, update the labels of u by u* and du*+ w(u*,
u), respectively.
The shortest paths (identified by following nonnumeric labels backward from a destination
vertex in the left column to the source) and their lengths (given by numeric labels of the tree
vertices) are as follows:
The pseudocode of Dijkstra’s algorithm is given below. Note that in the following pseudocode,
VT contains a given source vertex and the fringe contains the vertices adjacent to it after
iteration 0 is completed.
CSE, SVIT 13
61
ADA BCS401
Analysis:
The time efficiency of Dijkstra’s algorithm depends on the data structures used for
implementing the priority queue and for representing an input graph itself.
CSE, SVIT 14
62
ADA BCS401
Efficiency is Θ(|V|2) for graphs represented by their weight matrix and the priority queue
implemented as an unordered array.
For graphs represented by their adjacency lists and the priority queue implemented as a min-
heap, it is in O (|E| log |V| )
Applications
Transportation planning and packet routing in communication networks, including the
Internet
Finding shortest paths in social networks, speech recognition, document formatting,
robotics, compilers, and airline crew scheduling.
CSE, SVIT 15
63
ADA BCS401
CSE, SVIT 16
64
ADA BCS401
5.1. Heaps
Heap is a partially ordered data structure that is especially suitable for implementing priority
queues. Priority queue is a multiset of items with an orderable characteristic called an item’s
priority, with the following operations:
CSE, SVIT 17
65
ADA BCS401
Properties of Heap
1. There exists exactly one essentially complete binary tree with n nodes. Its height is
equal to ⌊𝑙𝑜𝑔2𝑛⌋
2. The root of a heap always contains its largest element.
3. A node of a heap considered with all its descendants is also a heap.
4. A heap can be implemented as an array by recording its elements in the top down, left-
to-right fashion. It is convenient to store the heap’s elements in positions 1 through n
of such an array, leaving H[0] either unused or putting there a sentinel whose value is
greater than every element in the heap. In such a representation,
a. the parental node keys will be in the first ⌊n/2⌋. positions of the array, while the
leaf keys will occupy the last ⌊n/2⌋ positions;
b. the children of a key in the array’s parental position i (1≤ i ≤⌊𝑛/2⌋) will be in
positions 2i and 2i + 1, and, correspondingly, the parent of a key in position i (2
≤ i≤ n) will be in position ⌊𝑛/2⌋.
CSE, SVIT 18
66
ADA BCS401
Constructions of Heap - There are two principal alternatives for constructing Heap.
1) Bottom-up heap construction 2) Top-down heap construction
CSE, SVIT 19
67
ADA BCS401
Illustration
Bottom-up construction of a heap for the list 2, 9, 7, 6, 5, 8. The double headed arrows show
key comparisons verifying the parental dominance.
CSE, SVIT 20
68
ADA BCS401
to find the larger child and the other to determine whether the exchange is required—the total
number of key comparisons involving a key on level I will be 2(h − i).
Therefore, the total number of key comparisons in the worst case will be
where the validity of the last equality can be proved either by using the closed-form formula
Delete an item from a heap: Deleting the root’s key from a heap can be done with the
following algorithm:
Maximum Key Deletion from a heap
1. Exchange the root’s key with the last key K of the heap.
2. Decrease the heap’s size by 1.
3. “Heapify” the smaller tree by sifting K down the tree exactly in the same way we did it
in the bottom-up heap construction algorithm. That is, verify the parental dominance
CSE, SVIT 21
69
ADA BCS401
for K: if it holds, we are done; if not, swap K with the larger of its children and repeat
this operation until the parental dominance condition holds for K in its new position.
Illustration
CSE, SVIT 22
70
ADA BCS401
Analysis of efficiency: Since we already know that the heap construction stage of the algorithm
is in O(n), we have to investigate just the time efficiency of the second stage. For the number
of key comparisons, C(n), needed for eliminating the root keys from the heaps of diminishing
sizes from n to 2, we get the following inequality:
This means that C(n) ∈ O(n log n) for the second stage of heapsort. For both stages, we get
O(n) + O(n log n) = O(n log n). A more detailed analysis shows that the time efficiency of
heapsort is, in fact, in Θ(n log n) in both the worst and average cases. Thus, heapsort’s time
efficiency falls in the same class as that of mergesort.
Heapsort is in-place, i.e., it does not require any extra storage. Timing experiments on random
files show that heapsort runs more slowly than quicksort but can be competitive with mergesort.
*****
CSE, SVIT 23
71
Lecture Notes on
Analysis and Design of Algorithms
BCS401
Contents
72
ADA BCS401
Example 1
Example 2
Example 3
Example 4
CSE, SVIT 1
73
ADA BCS401
CSE, SVIT 2
74
ADA BCS401
CSE, SVIT 3
75
ADA BCS401
CSE, SVIT 4
76
ADA BCS401
CSE, SVIT 5
77
ADA BCS401
Backward Approach
CSE, SVIT 6
78
ADA BCS401
(a) Digraph. (b) Its adjacency matrix. (c) Its transitive closure.
We can generate the transitive closure of a digraph with the help of depth first search or
breadth-first search. Performing either traversal starting at the ith vertex gives the information
about the vertices reachable from it and hence the columns that contain 1’s in the ith row of
the transitive closure. Thus, doing such a traversal for every vertex as a starting point yields
the transitive closure in its entirety.
Since this method traverses the same digraph several times, we can use a better algorithm
called Warshall’s algorithm. Warshall’s algorithm constructs the transitive closure through
a series of n × n boolean matrices:
Each of these matrices provides certain information about directed paths in the digraph.
Specifically, the element𝑟𝑖𝑗(𝑘) in the ith row and jth column of matrix R(k) (i, j = 1, 2, . . . , n, k =
0, 1, . . . , n) is equal to 1 if and only if there exists a directed path of a positive length from
the ith vertex to the jth vertex with each intermediate vertex, if any, numbered not higher than
k.
Thus, the series starts with R(0), which does not allow any intermediate vertices in its paths;
hence, R(0) is nothing other than the adjacency matrix of the digraph. R(1) contains the
information about paths that can use the first vertex as intermediate. The last matrix in the
series, R(n),reflects paths that can use all n vertices of the digraph as intermediate and hence is
nothing other than the digraph’s transitive closure.
This means that there exists a path from the ith vertex vi to the jth vertex vj with each
intermediate vertex numbered not higher than k:
vi, a list of intermediate vertices each numbered not higher than k, vj . --- (*)
Two situations regarding this path are possible.
CSE, SVIT 7
79
ADA BCS401
1. In the first, the list of its intermediate vertices does not contain the kth vertex. Then this
path from vi to vj has intermediate vertices numbered not higher than k−1. i.e. rij(k−1) = 1
th
2. The second possibility is that path (*) does contain the k vertex vk among the
intermediate vertices. Then path (*) can be rewritten as;
vi, vertices numbered ≤ k − 1, vk, vertices numbered ≤ k − 1, vj .
i.e r(k−1) = 1 and r(k−1) = 1
ik kj
Thus, we have the following formula for generating the elements of matrix R(k) from the
elements of matrix R(k−1)
As an example, the application of Warshall’s algorithm to the digraph is shown below. New
1’s are in bold.
CSE, SVIT 8
80
ADA BCS401
Analysis
Its time efficiency is Θ(n3). We can make the algorithm to run faster by treating matrix rows
as bit strings and employ the bitwise or operation available in most modern computer
languages.
Space efficiency: Although separate matrices for recording intermediate results of the
algorithm are used, that can be avoided.
(a) Digraph. (b) Its weight matrix. (c) Its distance matrix
We can generate the distance matrix with an algorithm that is very similar to Warshall’s
algorithm. It is called Floyd’s algorithm.
Floyd’s algorithm computes the distance matrix of a weighted graph with n vertices through a
series of n × n matrices:
CSE, SVIT 9
81
ADA BCS401
The element (𝑘)𝑖𝑗in the ith row and the jth column of matrix D(k) (i, j = 1, 2, . . . , n, k = 0, 1, .
. . , n) is equal to the length of the shortest path among all paths from the ith vertex to the jth
vertex with each intermediate vertex, if any, numbered not higher than k.
As in Warshall’s algorithm, we can compute all the elements of each matrix D(k) from its
immediate predecessor D(k−1)
Taking into account the lengths of the shortest paths in both subsets leads to the following
recurrence:
CSE, SVIT 10
82
ADA BCS401
Application of Floyd’s algorithm to the digraph is shown below. Updated elements are shown
in bold.
4. Knapsack problem
We start this section with designing a dynamic programming algorithm for the knapsack
problem: given n items of known weights w1, . . . ,wn and valuesv1, . . . , vn and a knapsack of
capacity W, find the most valuable subset of the items that fit into the knapsack. To design a
dynamic programming algorithm, we need to derive a recurrence relation that expresses a
solution to an instance of the knapsack problem in terms of solutions to its smaller sub
instances. Let us consider an instance defined by the first i items, 1≤ i ≤ n, with weights w1, . .
. ,wi, values v1, . . . , vi , and knapsack capacity j, 1 ≤ j ≤ W. Let F(i, j) be the value of an
optimal solution to this instance. We can divide all the subsets of the first i items that fit the
knapsack of capacity j into two categories: those that do not include the ith item and those that
do. Note the following:
CSE, SVIT 11
83
ADA BCS401
i. Among the subsets that do not include the ith item, the value of an optimal subset is,
by definition, i.e F(i , j) = F(i − 1, j).
ii. Among the subsets that do include the ith item (hence, j − wi≥ 0), an optimal subset is
made up of this item and an optimal subset of the first i−1 items that fits into the
knapsack of capacity j − wi. The value of such an optimal subset is vi+ F(i − 1, j − wi).
Thus, the value of an optimal solution among all feasible subsets of the first I items is the
maximum of these two values.
CSE, SVIT 12
84
ADA BCS401
We can find the composition of an optimal subset by back tracing the computations of this
entry in the table. Since F(4, 5) > F(3, 5), item 4 has to be included in an optimal solution
along with an optimal subset for filling 5 − 2 = 3 remaining units of the knapsack capacity.
The value of the latter is F(3, 3). Since F(3, 3) = F(2, 3), item 3 need not be in an optimal
subset. Since F(2, 3) > F(1, 3), item 2 is a part of an optimal selection, which leaves element
F(1, 3 − 1) to specify its remaining composition. Similarly, since F(1, 2) > F(0, 2), item 1 is
the final part of the optimal solution {item 1, item 2, item 4}.
Analysis
The time efficiency and space efficiency of this algorithm are both in Θ(nW). The time
needed to find the composition of an optimal solution is in O(n).
Memory Functions
The direct top-down approach to finding a solution to such a recurrence leads to an algorithm
that solves common subproblems more than once and hence is very inefficient.
The classic dynamic programming approach, on the other hand, works bottom up: it fills a
table with solutions to all smaller subproblems, but each of them is solved only once. An
unsatisfying aspect of this approach is that solutions to some of these smaller subproblems
are often not necessary for getting a solution to the problem given. Since this drawback is not
present in the top-down approach, it is natural to try to combine the strengths of the top-down
and bottom-up approaches. The goal is to get a method that solves only subproblems that are
necessary and does so only once. Such a method exists; it is based on using memory
functions.
This method solves a given problem in the top-down manner but, in addition, maintains a
table of the kind that would have been used by a bottom-up dynamic programming algorithm.
CSE, SVIT 13
85
ADA BCS401
Initially, all the table’s entries are initialized with a special “null” symbol to indicate that they
have not yet been calculated. Thereafter, whenever a new value needs to be calculated, the
method checks the corresponding entry in the table first: if this entry is not “null,” it is simply
retrieved from the table; otherwise, it is computed by the recursive call whose result is then
recorded in the table.
The following algorithm implements this idea for the knapsack problem. After initializing the
table, the recursive function needs to be called with i = n (the number of items) and j = W
(the knapsack capacity).
AlgorithmMFKnapsack(i, j )
//Implements the memory function method for the knapsack problem
//Input: A nonnegative integer i indicating the number of the first items being
considered and a nonnegative integer j indicating the knapsack capacity
//Output: The value of an optimal feasible subset of the first i items
//Note: Uses as global variables input arrays Weights[1..n], Values[1..n],and
table F[0..n, 0..W ] whose entries are initialized with −1’s except for
row 0 and column 0 initialized with 0’s
Example-2 Let us apply the memory function method to the instance considered in Example
1. The table in Figure given below gives the results. Only 11 out of 20nontrivial values (i.e.,
not those in row 0 or in column 0) have been computed. Just one nontrivial entry, V (1, 2), is
retrieved rather than being recomputed. For larger instances, the proportion of such entries
can be significantly larger.
Figure: Example of solving an instance of the knapsack problem by the memory function algorithm
In general, we cannot expect more than a constant-factor gain in using the memory function
method for the knapsack problem, because its time efficiency class is the same as that of the
bottom-up algorithm
CSE, SVIT 14
86
ADA BCS401
Problem definition: Given a graph and a source vertex s in graph, find shortest paths
from s to all vertices in the given graph. The graph may contain negative weight edges.
Note that we have discussed Dijkstra’s algorithm for single source shortest path problem.
Dijksra’s algorithm is a Greedy algorithm and time complexity is O(VlogV). But Dijkstra
doesn’t work for graphs with negative weight edges.
Bellman-Ford works for such graphs. Bellman-Ford is also simpler than Dijkstra and suites
well for distributed systems. But time complexity of Bellman-Ford is O(VE), which is more
than Dijkstra.
How it works? - Like other Dynamic Programming Problems, the algorithm calculates
shortest paths in bottom-up manner. It first calculates the shortest distances for the shortest
paths which have at-most one edge in the path. Then, it calculates shortest paths with at-most
2 edges, and so on.
Iteration i finds all shortest paths that use i edges. There can be maximum |V| – 1 edges in
any simple path, that is why the outer loop runs |v| – 1 times. The idea is, assuming that there
is no negative weight cycle, if we have calculated shortest paths with at most i edges, then an
iteration over all edges guarantees to give shortest path with at-most (i+1) edges
CSE, SVIT 15
87
ADA BCS401
CSE, SVIT 16
88
ADA BCS401
Another example
Figure: Steps of the Bellman Ford algorithm. The numbers with red squares indicate what changed on
each step.
CSE, SVIT 17
89
ADA BCS401
CSE, SVIT 18
90
ADA BCS401
CSE, SVIT 19
91
ADA BCS401
***
7. Space-Time Tradeoffs
Introduction
The main idea is to preprocess the problem’s input, in whole or in part, and store the additional
information obtained to accelerate solving the problem afterward. We call this approach as input
enhancement. The algorithms based on this approach are:
Sorting by Counting
The main idea here is to use the count variable. This variable shall give us the position of
the elements in its sorted order. Keeping the count variable as reference we can copy the elements
to a new list, so that we have a sorted list with us. The algorithm to do his is called the comparison
counting sort.
CSE, SVIT 20
92
93
94
Input Enhancement in String Matching- Harspool’s algorithm.
95
96
97
98
Lecture Notes on
Analysis and Design of Algorithms
BCS401
Module-5 : Backtracking
Contents
99
ADA BCS401
1. Backtracking
Some problems can be solved, by exhaustive search. The exhaustive-search technique
suggests generating all candidate solutions and then identifying the one (or the ones) with a
desired property.
Backtracking is a more intelligent variation of this approach. The principal idea is to
construct solutions one component at a time and evaluate such partially constructed
candidates as follows. If a partially constructed solution can be developed further without
violating the problem’s constraints, it is done by taking the first remaining legitimate option
for the next component. If there is no legitimate option for the next component, no
alternatives for any remaining component need to be considered. In this case, the algorithm
backtracks to replace the last component of the partially constructed solution with its next
option.
It is convenient to implement this kind of processing by constructing a tree of choices being
made, called the state-space tree. Its root represents an initial state before the search for a
solution begins. The nodes of the first level in the tree represent the choices made for the first
component of a solution; the nodes of the second level represent the choices for the second
component, and soon. A node in a state-space tree is said to be promising if it corresponds to
a partially constructed solution that may still lead to a complete solution; otherwise, it is
called non-promising. Leaves represent either non-promising dead ends or complete
solutions found by the algorithm.
In the majority of cases, a statespace tree for a backtracking algorithm is constructed in the
manner of depth-first search. If the current node is promising, its child is generated by adding
the first remaining legitimate option for the next component of a solution, and the processing
moves to this child. If the current node turns out to be non-promising, the algorithm
backtracks to the node’s parent to consider the next possible option for its last component; if
there is no such option, it backtracks one more level up the tree, and so on. Finally, if the
algorithm reaches a complete solution to the problem, it either stops (if just one solution is
required) or continues searching for other possible solutions.
CSE, SVIT 1
100
ADA BCS401
CSE, SVIT 2
101
ADA BCS401
CSE, SVIT 3
102
ADA BCS401
We start with the empty board and then place queen 1 in the first possible position of its row,
which is in column 1 of row 1. Then we place queen 2, after trying unsuccessfully columns 1
and 2, in the first acceptable position for it, which is square (2, 3), the square in row 2 and
column 3. This proves to be a dead end because there is no acceptable position for queen 3.
So, the algorithm backtracks and puts queen 2 in the next possible position at (2, 4). Then
queen 3 is placed at (3, 2), which proves to be another dead end. The algorithm then
backtracks all the way to queen 1 and moves it to (1, 2). Queen 2 then goes to (2, 4), queen 3
to(3, 1), and queen 4 to (4, 3), which is a solution to the problem. The state-space tree of this
search is shown in figure.
If other solutions need to be found, the algorithm can simply resume its operations at the leaf
at which it stopped. Alternatively, we can use the board’s symmetry for this purpose.
Finally, it should be pointed out that a single solution to the n-queens problem for any n ≥ 4
can be found in linear time.
Note: The algorithm NQueens() is not in the syllabus. It is given here for interested learners.
The algorithm is referred from textbook T2.
CSE, SVIT 4
103
ADA BCS401
CSE, SVIT 5
104
ADA BCS401
The root of the tree represents the starting point, with no decisions about the given elements
made as yet. Its left and right children represent, respectively, inclusion and exclusion of a1 in
a set being sought.
Similarly, going to the left from a node of the first level corresponds to inclusion of a2 while
going to the right corresponds to its exclusion, and so on. Thus, a path from the root to a node
on the ith level of the tree indicates which of the first in numbers have been included in the
subsets represented by that node.
We record the value of s, the sum of these numbers, in the node. If s is equal to d, we have a
solution to the problem. We can either report this result and stop or, if all the solutions need
to be found, continue by backtracking to the node’s parent. If s is not equal to d, we can
terminate the node as non-promising if either of the following two inequalities holds:
Example: Apply backtracking to solve the following instance of the subset sum problem: A
= {1, 3, 4, 5} and d = 11.
CSE, SVIT 6
105
ADA BCS401
CSE, SVIT 7
106
ADA BCS401
CSE, SVIT 8
107
ADA BCS401
Analysis
CSE, SVIT 9
108
ADA BCS401
CSE, SVIT 10
109
ADA BCS401
CSE, SVIT 11
110
ADA BCS401
CSE, SVIT 12
111
ADA BCS401
How can we find a lower bound on the cost of an optimal selection without actually solving
the problem?
We can do this by several methods. For example, it is clear that the cost of any solution,
including an optimal one, cannot be smaller than the sum of the smallest elements in each
of the matrix’s rows. For the instance here, this sum is 2 + 3+ 1+ 4 = 10.We can and will
apply the same thinking to partially constructed solutions. For example, for any legitimate
selection that selects 9 from the first row, the lower bound will be 9 + 3 + 1+ 4 = 17.
Rather than generating a single child of the last promising node as we did in backtracking, we
will generate all the children of the most promising node among non-terminated leaves in the
current tree. (Non terminated, i.e., still promising, leaves are also called live.) How can we
tell which of the nodes is most promising? We can do this by comparing the lower bounds of
the live nodes. It is sensible to consider a node with the best bound as most promising,
although this does not, of course, preclude the possibility that an optimal solution will
ultimately belong to a different branch of the state-space tree. This variation of the strategy is
called the best-first branch-and-bound.
We start with the root that corresponds to no elements selected from the cost matrix. The
lower-bound value for the root, denoted lb, is 10. The nodes on the first level of the tree
correspond to selections of an element in the first row of the matrix, i.e., a job for person a.
See the figure given below.
Figure: Levels 0 and 1 of the state-space tree for the instance of the assignment
problem being solved with the best-first branch-and-bound algorithm. The number
above a node shows the order in which the node was generated. A node’s fields
indicate the job number assigned to person a and the lower bound value, lb, for this
node.
So we have four live leaves—nodes 1 through 4—that may contain an optimal solution. The
most promising of them is node 2 because it has the smallest lower bound value. Following
our best-first search strategy, we branch out from that node first by considering the three
different ways of selecting an element from the second row and not in the second column -
the three different jobs that can be assigned to person b. See the figure given below (Fig
12.7).
CSE, SVIT 13
112
ADA BCS401
Of the six live leaves—nodes 1, 3, 4, 5, 6, and 7—that may contain an optimal solution, we
again choose the one with the smallest lower bound, node 5. First, we consider selecting the
third column’s element from c’s row (i.e., assigning person c to job 3); this leaves us with no
choice but to select the element from the fourth column of d’s row (assigning person d to job
4). This yields leaf 8 (Figure 12.7), which corresponds to the feasible solution {a→2, b→1,
c→3, d →4} with the total cost of 13. Its sibling, node 9, corresponds to the feasible solution
{a→2,b→1, c→4, d →3} with the total cost of 25. Since its cost is larger than the cost of the
solution represented by leaf 8, node 9 is simply terminated. (Of course, if its cost were
smaller than 13, we would have to replace the information about the best solution seen so far
with the data provided by this node.)
Now, as we inspect each of the live leaves of the last state-space tree—nodes1, 3, 4, 6, and 7
in Figure 12.7—we discover that their lower-bound values are not smaller than 13, the value
of the best selection seen so far (leaf 8). Hence, we terminate all of them and recognize the
solution represented by leaf 8 as the optimal solution to the problem.
CSE, SVIT 14
113
ADA BCS401
But there is a less obvious and more informative lower bound for instances with symmetric
matrix D, which does not require a lot of work to compute. We can compute a lower bound
on the length l of any tour as follows. For each city i, 1≤ i ≤ n, find the sum si of the distances
from city i to the two nearest cities; compute the sums of these n numbers, divide the result
by 2, and, if all the distances are integers, round up the result to the nearest integer:
lb = ⌈s/2⌉... (1)
For example, for the instance in Figure 2.2a, formula (1) yields
Moreover, for any subset of tours that must include particular edges of a given graph, we can
modify lower bound (formula 1) accordingly. For example, for all the Hamiltonian circuits of
the graph in Figure 2.2a that must include edge (a, d), we get the following lower bound by
summing up the lengths of the two shortest edges incident with each of the vertices, with the
required inclusion of edges (a, d)and (d, a):
We now apply the branch-and-bound algorithm, with the bounding function given by
formula-1, to find the shortest Hamiltonian circuit for the graph in Figure 2.2a.
To reduce the amount of potential work, we take advantage of two observations.
1. First, without loss of generality, we can consider only tours that start at a.
2. Second, because our graph is undirected, we can generate only tours in which b is
visited before c. (Refer Note at the end of section 2.2 for more details)
In addition, after visiting n−1= 4 cities, a tour has no choice but to visit the remaining
unvisited city and return to the starting one. The state-space tree tracing the algorithm’s
application is given in Figure 2.2b.
Note: An inspection of graph with 4 nodes (figure given below) reveals three pairs of tours
that differ only by their direction. Hence, we could cut the number of vertex permutations by
half. We could, for example, choose any two intermediate vertices, say, b and c, and then
consider only permutations in which b precedes c. (This trick implicitly defines a tour’s
direction.)
Figure: Solution to a small instance of the traveling salesman problem by exhaustive search.
CSE, SVIT 15
114
ADA BCS401
Figure 2.2(a)Weighted graph. (b) State-space tree of the branch-and-bound algorithm to find
a shortest Hamiltonian circuit in this graph. The list of vertices in a node specifies a
beginning part of the Hamiltonian circuits represented by the node.
Discussion
The strengths and weaknesses of backtracking are applicable to branch-and-bound as well.
The state-space tree technique enables us to solve many large instances of difficult
combinatorial problems. As a rule, however, it is virtually impossible to predict which
instances will be solvable in a realistic amount of time and which will not.
In contrast to backtracking, solving a problem by branch-and-bound has both the challenge
and opportunity of choosing the order of node generation and finding a good bounding
function. Though the best-first rule we used above is a sensible approach, it may or may not
lead to a solution faster than other strategies. (Artificial intelligence researchers are
particularly interested in different strategies for developing state-space trees.)
Finding a good bounding function is usually not a simple task. On the one hand, we want this
function to be easy to compute. On the other hand, it cannot be too simplistic - otherwise, it
would fail in its principal task to prune as many branches of a state-space tree as soon as
possible. Striking a proper balance between these two competing requirements may require
intensive experimentation with a wide variety of instances of the problem in question.
CSE, SVIT 16
115
ADA BCS401
Each node on the ith level of state space tree, 0 ≤ i ≤ n, represents all the subsets of n items
that include a particular selection made from the first i ordered items. This particular
selection is uniquely determined by the path from the root to the node: a branch going to the
left indicates the inclusion of the next item, and a branch going to the right indicates its
exclusion.
We record the total weight w and the total value v of this selection in the node, along with
some upper bound ub on the value of any subset that can be obtained by adding zero or more
items to this selection. A simple way to compute the upper bound ub is to add to v, the total
value of the items already selected, the product of the remaining capacity of the knapsack W
– w and the best per unit payoff among the remaining items, which is vi+1/wi+1:
ub = v + (W − w)(vi+1/wi+1).
Example: Consider the following problem. The items are already ordered in descending order
of their value-to-weight ratios.
Let us apply the branch-and-bound algorithm. At the root of the state-space tree (see Figure
12.8), no items have been selected as yet. Hence, both the total weight of the items already
selected w and their total value v are equal to 0. The value of the upper bound is 100.
Node 1, the left child of the root, represents the subsets that include item 1. The total weight
and value of the items already included are 4 and 40, respectively; the value of the upper
bound is 40 + (10 − 4) * 6 = 76.
CSE, SVIT 17
116
ADA BCS401
Node 2 represents the subsets that do not include item 1. Accordingly, w = 0, v = 0, and ub =
0 + (10 − 0) * 6 = 60. Since node 1 has a larger upper bound than the upper bound of node 2,
it is more promising for this maximization problem, and we branch from node 1 first. Its
children—nodes 3 and 4—represent subsets with item 1 and with and without item 2,
respectively. Since the total weight w of every subset represented by node 3 exceeds the
knapsack’s capacity, node 3 can be terminated immediately.
Node 4 has the same values of w and v as its parent; the upper bound ub is equal to 40 + (10
− 4) * 5 = 70. Selecting node 4 over node 2 for the next branching (Due to better ub), we get
nodes 5 and 6 by respectively including and excluding item 3. The total weights and values as
well as the upper bounds for these nodes are computed in the same way as for the preceding
nodes.
Branching from node 5 yields node 7, which represents no feasible solutions, and node 8,
which represents just a single subset {1, 3} of value 65. The remaining live nodes 2 and 6
have smaller upper-bound values than the value of the solution represented by node 8. Hence,
both can be terminated making the subset {1, 3} of node 8 the optimal solution to the
problem.
CSE, SVIT 18
117
ADA BCS401
preceding subsection.) For the knapsack problem, however, every node of the tree represents
a subset of the items given. We can use this fact to update the information about the best
subset seen so far after generating each new node in the tree. If we had done this for the
instance investigated above, we could have terminated nodes 2 and 6 before node 8 was
generated because they both are inferior to the subset of value 65 of node 5.
CSE, SVIT 19
118
ADA BCS401
CSE, SVIT 20
119
ADA BCS401
CSE, SVIT 21
120
ADA BCS401
CSE, SVIT 22
121
ADA BCS401
CSE, SVIT 23
122
ADA BCS401
Conclusion
CSE, SVIT 24
123
ADA BCS401
CSE, SVIT 25
124
ADA BCS401
print(‘0’); failure
procedure NSORT(A,n);
//sort n positive integers//
var integer A(n), B(n), n, i, j;
begin
B := 0; //B is initialized to zero//
for i := 1 to n do
begin
j := choice(1:n);
if B(j) <> 0 then failure;
B(j) := A(j);
end;
CSE, SVIT 26
125
ADA BCS401
But there are some problems which are known to be in NP but don’t know if they’re in P. The
traditional example is the decision-problem version of the Travelling Salesman Problem
(decision-TSP). It’s not known whether decision-TSP is in P: there’s no known poly-time
solution, but there’s no proof such a solution doesn’t exist.
There are problems that are known to be neither in P nor NP; a simple example is to
enumerate all the bit vectors of length n. No matter what, that takes 2n steps.
Now, one more concept: given decision problems P and Q, if an algorithm can transform a
solution for P into a solution for Q in polynomial time, it’s said that Q is poly-time
reducible (or just reducible) to P.
The most famous unsolved problem in computer science is “whether P=NP or P≠NP? ”
CSE, SVIT 27
126
ADA BCS401
NP-Complete problems have the property that it can be solved in polynomial time if all other
NP-Complete problems can be solved in polynomial time. i.e if anyone ever finds a poly-time
solution to one NP-complete problem, they’ve automatically got one for all the NP-complete
problems; that will also mean that P=NP.
Example for NP-complete is CNF-satisfiability problem. The CNF-satisfiability problem
deals with boolean expressions. This is given by Cook in 1971. The CNF-satisfiability
problem asks whether or not one can assign values true and false to variables of a given
boolean expression in its CNF form to make the entire expression true.
Over the years many problems in NP have been proved to be in P (like Primality Testing).
Still, there are many problems in NP not proved to be in P. i.e. the question still remains
whether P=NP? NP Complete Problems helps in solving this question. They are a subset
of NP problems with the property that all other NP problems can be reduced to any of them in
polynomial time. So, they are the hardest problems in NP, in terms of running time. If it can
be showed that any NP-Complete problem is in P, then all problems in NP will be in P
(because of NP-Complete definition), and hence P=NP=NPC.
NP Hard Problems - These problems need not have any bound on their running time. If
any NP-Complete Problem is polynomial time reducible to a problem X, that problem X
belongs to NP-Hard class. Hence, all NP-Complete problems are also NP-Hard. In other
words if a NP-Hard problem is non-deterministic polynomial time solvable, it is a NP-
Complete problem. Example of a NP problem that is not NPC is Halting Problem.
If a NP-Hard problem can be solved in polynomial time then all NP-Complete can be solved
in polynomial time.
“All NP-Complete problems are NP-Hard but not all NP-Hard problems are not NP-
Complete.”NP-Complete problems are subclass of NP-Hard
The more conventional optimization version of Traveling Salesman Problem for finding the
shortest route is NP-hard, not strictly NP-complete.
*****
CSE, SVIT 28
127
BCS401
Model Question Paper with effect from 2023-24 (CBCS Scheme)
USN
Note: 01. Answer any FIVE full questions, choosing at least ONE question from each MODULE.
Module -1 BL Marks
Q.01 a Define algorithm. Explain asymptotic notations Big Oh, Big Omega and Big Theta L2 08
notations
b Explain the general plan for analyzing the efficiency of a recursive algorithm. Suggest L2 08
a recursive algorithm to find factorial of number. Derive its efficiency
c If t1(n) ∈ O(g1(n)) and t2(n) ∈ O(g2(n)), then show that t1(n) + t2(n) ∈ O(max{g1(n), L2 04
g2(n)}).
OR
Q.02 a With neat diagram explain different steps in designing and analyzing an algorithm L2 08
b Explain the general plan for analyzing the efficiency of a non-recursive algorithm. L2 08
Suggest a non-recursive algorithm to find maximum element in the list of n numbers.
Derive its efficiency
c With the algorithm derive the worst case efficiency for Bubble sort L2 04
Module-2
Q. 03 a Explain the concept of divide and conquer. Design an algorithm for merge sort and L2 10
derive its time complexity
b Design an insertion sort algorithm and obtain its time complexity. Apply insertion sort L3 10
on these elements. 25,75,40,10,20,
OR
Q.04 a Explain Strassen’s matrix multiplication and derive its time complexity L2 10
b Design an algorithm for quick sort algorithm. Apply quick sort on these elements. L3 10
25,75,40,10,20,05,15
Module-3
Q. 05 a Define AVL Trees. Explain its four rotation types L2 10
b Construct bottom up heap for the list 2,9,7,6,5,8. Obtain its time complexity L3 10
OR
Q. 06 a Define heap. Explain the properties of heap along with its representation. L2 10
b Design Horspools algorithm for string matching. Apply Horspools algorithm to find L3 10
the pattern BARBER in the text: JIM_SAW_ME_IN_A_BARBERSHOP
Module-4
Q. 07 a Construct minimum cost spanning tree using Kruskals algorithm for the following L3 10
graph.
b What are Huffman Trees? Construct the Huffman tree for the following data. L3 10
Character A B C D E -
Probability 0.5 0.35 0.5 0.1 0.4 0.2
Encode DAD-CBE using Huffman Encoding.
Page 01 of 02
128
BCS401
OR
Q. 08 a Apply Dijkstra’s algorithm to find single source shortest path for the given graph by L3 10
considering S as the source vertex.
Module-5
Q. 09 a Explain the following with examples L2 10
i) P problem
ii) NP Problem
iii) NP- Complete problem
iv) NP – Hard Problems
b What is backtracking? Apply backtracking to solve the below instance of sum of subset L3 10
problem S={5,10,12,13,15,18} d=30
OR
Q. 10 a Illustrate N queen’s problem using backtracking to solve 4-Queens problem L2 10
b Using Branch and Bound technique solve the below instance of knapsack problem. L3 10
Item Weight Value
1 2 12
2 1 10
3 3 20
4 2 5
Capacity 5
Page 02 of 02
129