DAA LectureNote
DAA LectureNote
This course teaches techniques for designing efficient algorithms and analyzing their
performance. Students learn common algorithmic strategies and complexity analysis to solve
computational problems effectively.
Course Objectives:
1.1. Algorithm
1.2. Pseudo-code for expressing algorithms
1.3. Performance Analysis-Space complexity
1.4. Time complexity
1.5. Asymptotic Notation- Big oh-notation
1.6. Omega notation
1.7. Theta notation and little oh-notation
1.8. Probabilistic Analysis
1.9. Amortized Analysis
Description:
Objectives:
1. Natural language like English: When this way is choused care should be taken, we should ensure
that each & every statement is definite.
3. Pseudo-code Method: In this method, we should typically describe algorithms as program, which
resembles language like C and C++
Performance Analysis:
The performance of a program is the amount of computer memory and time needed to run a program. We
use two approaches to determine the performance of a program. One is analytical, and the other
experimental. In performance analysis we use analytical methods, while in performance measurement we
conduct experiments.
With ever-increasing computer speeds, one might ask why we still need to analyze algorithms. The answer lies in
scalability. A poor algorithm on a fast machine will almost always be outperformed by a superior algorithm on a
slower machine for large inputs. Algorithm analysis gives us a mathematical way to predict and compare the
performance of different algorithms without having to implement and run them.
Time Complexity: The amount of computational time the algorithm needs to run.
Space Complexity: The amount of memory the algorithm needs to run.
We are primarily interested in the growth rate of these resources as the input size (n) increases.
Asymptotic Notations:
Asymptotic notations are mathematical tools used to describe the running time of an algorithm in
relation to the input size .
Big O (O): Represents the upper bound of an algorithm's running time. It describes the
worst-case scenario. For example, if we say an algorithm has a time complexity of O(n²),
it means the running time grows at most quadratically with the input size.
Big Omega (Ω): Represents the lower bound of an algorithm's running time. It describes
the best-case scenario.
Big Theta (Θ): Represents the tight bound of an algorithm's running time. It means the
algorithm's running time is bounded both above and below by the same function. For
Little Oh Notation: The little Oh is denoted as o. It is defined as : Let, f(n} and g(n} be the
non-negative functions then
In order to perform a probabilistic analysis, we must use knowledge of, or make assumptions
about, the distribution of the inputs. Then we analyze our algorithm, computing an average-case
running time, where we take the average over the distribution of the possible inputs.
Amortized Analysis:
Aggregate Analysis: in which we determine an upper bound T(n) on the total cost of a
sequence of n operations. The average cost per operation is then T(n)/n. We take the
average cost as the amortized cost of each operation
Accounting method: When there is more than one type of operation, each type of
operation may have a different amortized cost. The accounting method overcharges some
operations early in the sequence, storing the overcharge as ―prepaid credit‖ on specific
objects in the data structure. Later in the sequence, the credit pays for operations that are
charged less than they actually cost.
Potential method - The potential method maintains the credit as the ―potential energy‖
of the data structure as a whole instead of associating the credit with individual objects
within the data structure. The potential method, which is like the accounting method in
that we determine the amortized cost of each operation and may overcharge operations
early on to compensate for undercharges later
Description:
Objectives:
Divide and conquer strategy is as follows: divide the problem instance into two or more smaller
instances of the same problem, solve the smaller instances recursively, and assemble the
solutions to form a solution of the original instance. The recursion stops when an instance is
reached which is too small to divide. When dividing the instance, one can either use whatever
division comes most easily to hand or invest time in making the division carefully so that the
assembly is simplified.
Divide: The main problem is broken down into smaller, identical sub-problems.
Conquer: The sub-problems are solved recursively. If a sub-problem is small enough (a
base case), it is solved directly.
Combine: The solutions to the sub-problems are combined to create a solution to the
original problem.
Binary Search:
Merge Sort:
Algorithm :
Quick Sort:
Algorithm:
Divide: Pick an element, called a pivot, from the array. Reorder the array so that all
elements with values less than the pivot come before the pivot, while all elements with
values greater than the pivot come after it (this is the partitioning step).
Conquer: Recursively apply the above steps to the sub-array of elements with smaller
values and separately to the sub-array of elements with greater values.
Combine: This step is trivial, as the array is sorted in place.
AKU| Design and Analysis of Algorithm – DAA Excellence through Perseverance!!(AKU)
11
Analysis:
o Worst-case: O(n²). This happens when the pivot is always the smallest or largest
element (e.g., on an already sorted array).
o Average/Best-case: Θ(n log n).
Description:
Objectives:
So we go on traversing all left node. As we visit the node. We will put that node into
[Link] need to visit parent after the child and as we will encounter parent first when
start from root. it's case for LIFO :) and hence the stack). Once we reach NULL node. We will
take the node at the top of the stack. Last node which we visited, Print it.
Check if there is right child to that node. If yes, move right child to stack and again start
traversing left child node and put them on to stack. Once we have traversed all nodes. Our stack
will be empty.
For presenting the union and find algorithms, we ignore the set names and identify sets just by
the roots of the trees representing them.
For example: if we determine that element ‗i‘ is in a tree with root ‗j‘ has a pointer to entry ‗k‘
in the set name table, then the set name is just name[k]
Example: If you wish to unite to Si and Sj then we wish to unite the tree with roots
FindPointeris a function that takes a set name and determines the root of the tree that
represents it.
Find(i)1St determine the root of the tree and find its pointer to entry in setname table.
P[1:n].
Find(i) by following the indices, starting at i until we reach a node with parent value -1.
Example: Find(6) start at 6 and then moves to 6‘s parent. Since P[3] is negative, we reached the root.
If n numbers of roots are there then the above algorithms are not useful for union and find.
For union of n treesUnion(1,2), Union(2,3), Union(3,4),…..Union(n-1,n).
For Find i in n treesFind(1), Find(2),….Find(n).
Time taken for the union (simple union) is O(1) (constant).
For the n-1 unionsO(n).
Collapsing rule: If ‗j‘ is a node on the path from ‗i‘ to its root and p[i]≠root[i], then set p[j] to
root[i].
Spanning Tree:-
Let G=(V<E) be an undirected connected graph. A sub graph t=(V,E1) of G is a spanning tree of G
iff t is a tree.
Prim’s Algorithm: Start with any one node in the spanning tree, and repeatedly add the cheapest
edge, and the node it leads to, for which the node is not already in the spanning tree.
Kruskal’s Algorithm: Start with no nodes or edges in the spanning tree, and repeatedly add the
cheapest edge that does not create a cycle.
Connected Component:
This is also called connected graph or spanning tree. Spanning trees obtained using BFS then it
called breadth first spanning trees.
There is an efficient algorithm to test whether a connected graph is bi-connected. If the case of
graphs that are not bi-connected, this algorithm will identify all the articulation points.
Once it has been determined that a connected graph G is not bi-connected, it may be desirable
(suitable) to determine a set of edges whose inclusion makes the graph bi-connected.
Description:
Objectives:
1. Greedy Choice Property: A global (overall) optimal solution can be reached by making a
locally optimal (best) choice.
2. Optimal Substructure: An optimal solution to the problem contains within it optimal
solutions to sub-problems.
Feasible solution: Most problems have n inputs and its solution contains a subset of inputs that
satisfies a given constraint (condition). Any subset that satisfies the constraint is called feasible
solution.
Optimal solution: To find a feasible solution that either maximizes or minimizes a given
objective function. A feasible solution that does this is called optimal solution.
The greedy method suggests that an algorithm works in stages, considering one input at a time.
At each stage, a decision is made regarding whether a particular input is in an optimal solution.
Greedy algorithms neither postpone nor revise the decisions (ie., no back tracking).
Example: Kruskal‘s minimal spanning tree. Select an edge from a sorted list, check, decide, and
never visit it again.
Knapsack problem:
Consider a knapsack of capacity 20. Determine the optimum strategy for placing the objects in to
the knapsack. The problem can be solved by the greedy approach where in the inputs are
arranged according to selection process (greedy strategy) and solve the problem in stages. The
various greedy strategies for the problem could be as follows.
Graphs can be used to represent the highway structure of a state or country with vertices
representing cities and edges representing sections of highway.
The edges have assigned weights which may be either the distance between the 2 cities
connected by the edge or the average time to drive along that section of highway.
For example if A motorist wishing to drive from city A to B then we must answer the
following questions
Is there a path from A to B
If there is more than one path from A to B which is the shortest path
The length of a path is defined to be the sum of the weights of the edges on that path.
AKU| Design and Analysis of Algorithm – DAA Excellence through Perseverance!!(AKU)
34
Given a directed graph G(V,E) with weight edge w(u,v). e have to find a shortest path from
source vertex S∈v to every other vertex v1∈ v-s.
To find SSSP for directed graphs G(V,E) there are two different algorithms.
Bellman-Ford Algorithm
Dijkstra‘s algorithm
Bellman-Ford Algorithm: allow –ve weight edges in input graph. This algorithm either
finds a shortest path form source vertex S∈V to other vertex v∈V or detect a –ve weight
cycles in G, hence no solution. If there is no negative weight cycles are reachable form
source vertex S∈V to every other vertex v∈V
Dijkstra‘s algorithm: allows only +ve weight edges in the input graph and finds a shortest
path from source vertex S∈V to every other vertex v∈V.
Consider the above directed graph, if node 1 is the source vertex, then shortest path from
1 to 2 is 1,4,5,2. The length is 10+15+20=45.
To formulate a greedy based algorithm to generate the shortest paths, we must conceive
of a multistage solution to the problem and also of an optimization measure.
As an optimization measure we can use the sum of the lengths of all paths so far
generated.
If we have already constructed ‗i‘ shortest paths, then using this optimization measure,
the next path to be constructed should be the next shortest minimum length path.
The greedy way to generate the shortest paths from Vo to the remaining vertices is to
generate these paths in non-decreasing order of path length.
For this 1st, a shortest path of the nearest vertex is generated. Then a shortest path to the
2nd nearest vertex is generated and so on.
Spanning Tree: A Sub graph ‗n‘ of o graph ‗G‘ is called as a spanning tree if
Minimum cost spanning tree: For a given graph ‗G‘ there can be more than one spanning tree.
If weights are assigned to the edges of ‗G‘ then the spanning tree which has the minimum cost of
edges is called as minimal spanning tree.
The greedy method suggests that a minimum cost spanning tree can be obtained by contacting
the tree edge by edge. The next edge to be included in the tree is the edge that results in a
minimum increase in the some of the costs of the edges included so far.
There are two basic algorithms for finding minimum-cost spanning trees, and both are greedy
algorithms
Prim‘s Algorithm
Kruskal‘s Algorithm
Prim’s Algorithm: Start with any one node in the spanning tree, and repeatedly add the cheapest
edge, and the node it leads to, for which the node is not already in the spanning tree.
Description:
Objectives:
When optimal decision sequences contain optimal decision subsequences, we can establish
recurrence equations, called dynamic-programming recurrence equations, that enable us to solve
the problem in an efficient way.
Dynamic programming is based on the principle of optimality (also coined by Bellman). The
principle of optimality states that no matter whatever the initial state and initial decision are, the
remaining decision sequence must constitute an optimal decision sequence with regard to the
state resulting from the first decision. The principle implies that an optimal decision sequence is
comprised of optimal decision subsequences. Since the principle of optimality may not hold for
some formulations of some problems, it is necessary to verify that it does hold for the problem
being solved. Dynamic programming cannot be applied when this principle does not hold.
Verify that the principle of optimality holds
Set up the dynamic-programming recurrence equations
Solve the dynamic-programming recurrence equations for the value of the optimal
solution.
Perform a trace back step in which the solution itself is constructed.
Dynamic programming differs from the greedy method since the greedy method produces only
one feasible solution, which may or may not be optimal, while dynamic programming produces
all possible sub-problems at most once, one of which guaranteed to be optimal. Optimal
solutions to sub-problems are retained in a table, thereby avoiding the work of re-computing the
answer every time a sub-problem is encountered.
There is no characterized precisely which problems can be effectively solved with dynamic
programming; there are many hard problems for which it does not seen to be applicable, as well
as many easy problems for which it is less efficient than standard algorithms.
A multistage graph G = (V, E) is a directed graph in which the vertices are partitioned into k > 2
disjoint sets Vi, 1 < i < k. In addition, if <u, v> is an edge in E, then u E Vi and v E Vi+1 for
some i, 1 < i < k.
Let the vertex ‗s‘ is the source, and ‗t‘ the sink. Let c (i, j) be the cost of edge <i, j>. The cost of
a path from ‗s‘ to ‗t‘ is the sum of the costs of the edges on the path. The multistage graph
problem is to find a minimum cost path from ‗s‘ to ‗t‘. Each set Vi defines a stage in the graph.
Because of the constraints on E, every path from ‗s‘ to ‗t‘ starts in stage 1, goes to stage 2, then
to stage 3, then to stage 4, and so on, and eventually terminates in stage k.
A dynamic programming formulation for a k-stage graph problem is obtained by first noticing
that every s to t path is the result of a sequence of k – 2 decisions. The ith decision involves
determining which vertex in vi+1, 1 < i < k - 2, is to be on the path. Let c (i, j) be the cost of the
path from source to destination. Then using the forward approach, we obtain:
cost (i, j) = min {c (j, l) + cost (i + 1, l)}
Complexity Analysis:
The complexity analysis of the algorithm is fairly straightforward. Here, if G has ~E~ edges,
then the time for the first for loop is CJ ( V~ +~E ).
Problem: Given n items, each with a weight w[i] and a value v[i], and a knapsack with
capacity W, what is the maximum value that can be carried? Unlike the fractional
version, an item must be taken entirely (1) or left behind (0).
DP Formulation :
Let dp[i][j] be the maximum value achievable using the first i items and a
capacity of j.
Recurrence: dp[i][j] = max( dp[i-1][j] , dp[i-1][j - w[i]] + v[i] ) for j >= w[i].
Problem: Given two sequences X and Y, find the longest subsequence that is common to
both .
Let L[i][j] be the length of the LCS of the first i characters of X and the
first j characters of Y.
Recurrence:
Problem: Find the shortest paths between every pair of vertices in a weighted graph
(allowing negative weights but no negative cycles).
DP Idea: Let dist[k][i][j] be the shortest path from i to j using only vertices from the
set {1, 2, ..., k} as intermediate vertices. The final solution is dist[n][i][j].
Recurrence: dist[k][i][j] = min( dist[k-1][i][j], dist[k-1][i][k] + dist[k-1][k][j] ).
This means either the best path using the first k-1 vertices is enough, or going
through k yields a shorter path.
Problem: Find the shortest path from a source s to all other vertices, even when edges
have negative weights.
DP Idea: Let dist[u][k] be the shortest path from s to u using at most k edges.
Recurrence: dist[u][k] = min( dist[u][k-1], min over all edges (v,u) of ( dist[v][k-1] +
w(v,u) ) ).
The algorithm runs for k = 1 to |V|-1 to find the best path.
Given a sequence of matrices A1, A2, A3, ..., An, find the best way (using the minimal number of
multiplications) to compute their product.
Let G = (V, E) be a directed graph with edge costs Cij. The variable cij is defined such that cij > 0 for
all I and j and cij = a if < i, j> o E. Let |V| = n and assume n > 1. A tour of G is a directed simple
cycle that includes every vertex in V. The cost of a tour is the sum of the cost of the edges on the
tour. The traveling sales person problem is to find a tour of minimum cost. The tour is to be a simple
path that starts and ends at vertex 1.
Let g (i, S) be the length of shortest path starting at vertex i, going through all vertices in S, and
terminating at vertex 1. The function g (1, V – {1}) is the length of an optimal salesperson tour. From
the principal of optimality it follows that:
g(1, V - {1 }) = 2 ~ k ~ n ~c1k ~ g ~ k, V ~ ~ 1, k ~~ ~
min
g ( i, S ) = min{ci j
The Equation can be solved for g (1, V – 1}) if we know g (k, V – {1, k}) for all choices of k.
Example 1: For the following graph find minimum cost tour for the traveling salesperson
problem:
Description:
Objectives:
N-Queens Problem: The goal is to place N chess queens on an N×N chessboard so that
no two queens threaten each other. The backtracking algorithm places queens one by one
in different columns, starting from the leftmost column. When placing a queen in a
column, it checks for clashes with already placed queens. If a clash is found, it backtracks
and returns false.
Sum of Subsets: Given a set of positive integers and a target sum, find all subsets that
sum to the target.
Graph Coloring: Given a graph, assign colors to vertices such that no two adjacent
vertices share the same color, using at most m colors.
Branch and Bound is a general algorithm for finding optimal solutions to various optimization
problems, especially in combinatorial optimization. It is similar to backtracking but is used for
optimization. Instead of stopping when a solution is found, it continues to search for a better one.
It uses a breadth-first or least-cost-first search strategy.
Key Idea: It maintains a global variable for the best solution found so far (the bound). While
traversing the state-space tree, it computes a bound at each node. If the bound of a node is worse
than the current global best solution, that branch is pruned, as it cannot lead to a better solution
than the one we already have.
Applications of Backtracking:
N Queens Problem
Sum of subsets problem
Graph coloring
AKU| Design and Analysis of Algorithm – DAA Excellence through Perseverance!!(AKU)
50
Hamiltonian cycles.
N-Queens Problem:
It is a classic combinatorial problem. The eight queen‘s puzzle is the problem of placing eight
queens puzzle is the problem of placing eight queens on an 8×8 chessboard so that no two
queens attack each other. That is so that no two of them are on the same row, column, or
diagonal.
The 8-queens puzzle is an example of the more general n-queens problem of placing n queens on
an n×n chessboard.
Given positive numbers wi 1 ≤ i ≤ n, & m, here sum of subsets problem is finding all subsets of w i
whose sums are m.
Definition: Given n distinct +ve numbers (usually called weights), desire (want) to find all
combinations of these numbers whose sums are m. this is called sum of subsets problem.
To formulate this problem by using either fixed sized tuples or variable sized tuples.
Graph Coloring:
Let G be a undirected graph and ‗m‘ be a given +ve integer. The graph coloring problem is
assigning colors to the vertices of an undirected graph with the restriction that no two adjacent
vertices are assigned the same color yet only ‗m‘ colors are used.
The optimization version calls for coloring a graph using the minimum number of coloring.
The decision version, known as K-coloring asks whether a graph is colorable using at most k-
colors.
Def: Let G=(V, E) be a connected graph with n vertices. A Hamiltonian cycle is a round
trip path along n-edges of G that visits every vertex once & returns to its starting position.
It is also called the Hamiltonian circuit.
Hamiltonian circuit is a graph cycle (i.e., closed loop) through a graph that visits each
node exactly once.
A graph possessing a Hamiltonian cycle is said to be Hamiltonian graph.
Example:
Two graph search strategies, BFS & D-search (DFS) in which the exploration of a new
node cannot begin until the node currently being explored is fully explored.
Both BFS & D-search (DFS) generalized to B&B strategies.
BFSlike state space search will be called FIFO (First In First Out) search as the list
of live nodes is ―First-in-first-out‖ list (or queue).
D-search (DFS)Like state space search will be called LIFO (Last In First Out)
search as the list of live nodes is a ―last-in-first-out‖ list (or stack).
In backtracking, bounding function are used to help avoid the generation of sub-trees that
do not contain an answer node.
We will use 3-types of search strategies in branch and bound
1) FIFO (First In First Out) search
Objectives:
Non-Deterministic: The algorithm in which the operations are not uniquely defined but are
limited to specific set of possibilities for every operation, such an algorithm is called non-
deterministic algorithm.
In case the successful completion is not possible, then the complexity is O(1). In case of
successful signal completion then the time required is the minimum number of steps needed to
reach a successful completion of O(n) where n is the number of inputs.
The problems that are solved in polynomial time are called tractable problems and the problems
that require super polynomial time are called non-tractable problems. All deterministic
polynomial time algorithms are tractable and the non-deterministic polynomials are intractable.
2. NP-Complete
NP-Hard: Problem can be solved in polynomial time then all NP-Complete problems can be
solved in polynomial time.
All NP-Complete problems are NP-Hard but some NP-Hard problems are not known to be NP-
Complete.
For measuring the complexity of an algorithm, we use the input length as the parameter. For
example, An algorithm A is of polynomial complexity p() such that the computing time of A is
O(p(n)) for every input of size n.
Decision problem/ Decision algorithm: Any problem for which the answer is either zero or one
is decision problem. Any algorithm for a decision problem is termed a decision algorithm.
Optimization problem/ Optimization algorithm: Any problem that involves the identification
of an optimal (either minimum or maximum) value of a given cost function is known as an
optimization problem. An optimization algorithm is used to solve an optimization problem.
P-) is the set of all decision problems solvable by deterministic algorithms in polynomial time.
NP-) is the set of all decision problems solvable by nondeterministic algorithms in polynomial
time.
Since deterministic algorithms are just a special case of nondeterministic, by this we concluded
that P ⊆ NP
If there any single problem in NP, such that if we showed it to be in ‗P‘ then that would imply
that P=NP.
Let L1 and L2 be problems, Problem L1 reduces to L2 (written L1 α L2) iff there is a way to
solve L1 by a deterministic polynomial time algorithm using a deterministic algorithm that
solves L2 in polynomial time
This implies that, if we have a polynomial time algorithm for L2, Then we can solve L1 in
polynomial time.
Cook’s Theorem: States that satisfiability is in P if and only if P=NP If P=NP then satisfiability
is in P
If satisfiability is in P, then P=NP
To do this
> A-) Any polynomial time nondeterministic decision algorithm.
I-)Input of that algorithm
Then formula Q(A, I), Such that Q is satisfiable iff ‗A’ has a successful termination with
Input I.
> If the length of ‗I‘ is ‗n’ and the time complexity of A is p(n) for some polynomial p()
then length of Q is O(p3(n) log n)=O(p4(n))
The time needed to construct Q is also O(p3(n) log n).
> A deterministic algorithm ‗Z’ to determine the outcome of ‗A‘ on any input ‗I‘
Algorithm Z computes ‗Q‘ and then uses a deterministic algorithm for the satisfiability
problem to determine whether ‗Q‘ is satisfiable.
> If O(q(m)) is the time needed to determine whether a formula of length ‗m‘ is
satisfiable then the complexity of ‗Z‘ is O(p3(n) log n + q(p3(n)log n)).
> If satisfiability is ‗p‘, then ‗q(m)‘ is a polynomial function of ‗m‘ and the
complexity of ‗Z‘ becomes ‗O(r(n))’ for some polynomial ‗r()’.