All Units Notes DAA
All Units Notes DAA
COURSE OBJECTIVES:
To understand and apply the algorithm analysis techniques on searching andsorting algorithms
To understand the different Greedy Algorithms
To understand different algorithm design techniques.
To solve programming problems using state space tree.
To understand the concepts behind NP Completeness, Approximation algorithms and
randomize algorithms.
UNIT I INTRODUCTION
9
Problem Solving: Programs and Algorithms – Problem Solving Aspects – Problem Solving
Techniques - Algorithm analysis: Time and space complexity - AsymptoticNotations and its
properties Best case, Worst case and average case analysis – Recurrence relation: substitution
method and searching: Interpolation Search, Pattern search: The naïve string- matching
algorithm - Rabin-Karp algorithm - Knuth-Morris-Pratt algorithm.
1
Course Code/Title:CS3302/Design Analysis of Algorithms
2
Course Code/Title:CS3302/Design Analysis of Algorithms
In order to effectively manage and run a successful organization, leadership must guide their
employees and develop problem-solving techniques. Finding a suitablesolution for issues can
be accomplished by following the basic four-step problem-solving process and methodology
outlined below.
3
Course Code/Title:CS3302/Design Analysis of Algorithms
Step Characteristics
4
Course Code/Title:CS3302/Design Analysis of Algorithms
Step Characteristics
Diagnose the situation so that your focus is on the problem, not just its symptoms. Helpful
problem-solving techniques include using flowcharts to identify the expected steps of a
process and cause-and-effect diagrams to define and analyze root causes.
The sections below help explain key problem-solving steps. These steps support the
involvement of interested parties, the use of factual information, comparison of
expectations to reality, and a focus on root causes of a problem. You should begin by:
Reviewing and documenting how processes currently work (i.e., who doeswhat, with what
information, using what tools, communicating with what organizations and individuals, in
what time frame, using what format).
Evaluating the possible impact of new tools and revised policies in thedevelopment of your
"what should be" model.
Postpone the selection of one solution until several problem-solving alternatives havebeen
proposed. Considering multiple alternatives can significantly enhance the value of your
ideal solution. Once you have decided on the "what should be" model, this target standard
becomes the basis for developing a road map for investigating alternatives. Brainstorming
and team problem-solving techniques are both useful tools in this stage of problem solving.
Many alternative solutions to the problem should be generated before final evaluation. A
common mistake in problem solving is that alternatives are evaluated as they are proposed,
so the first acceptable solution is chosen, even if it’s not the best fit. If we focus on trying
to get the results we want, we miss the potential for learning something new that will allow
for real improvement in the problem-solvingprocess.
5
Course Code/Title:CS3302/Design Analysis of Algorithms
Skilled problem solvers use a series of considerations when selecting the bestalternative.
They consider the extent to which:
A particular alternative will solve the problem without causing other unanticipated
problems.
All the individuals involved will accept the alternative.
Implementation of the alternative is likely.
The alternative fits within the organizational constraints.
Leaders may be called upon to direct others to implement the solution, "sell" the solution,
or facilitate the implementation with the help of others. Involving others in the
implementation is an effective way to gain buy-in and support and minimize resistance to
subsequent changes.
Regardless of how the solution is rolled out, feedback channels should be built into the
implementation. This allows for continuous monitoring and testing of actual events against
expectations. Problem solving, and the techniques used to gain clarity,are most effective if
the solution remains in place and is updated to respond to futurechanges.
6
Course Code/Title:CS3302/Design Analysis of Algorithms
7
Course Code/Title:CS3302/Design Analysis of Algorithms
8
Course Code/Title:CS3302/Design Analysis of Algorithms
is, you have to prove that the algorithm yields a required result for every legitimate input
in a finite amount of time.
A common technique for proving correctness is to use mathematical induction because
an algorithm’s iterations provide a natural sequence of steps needed forsuch proofs.
It might be worth mentioning that although tracing the algorithm’s performancefor a few
specific inputs can be a very worthwhile activity, it cannot prove the algorithm’s
correctness conclusively. But in order to show that an algorithm is incorrect, you need
just one instance of its input for which the algorithm fails.
Analysing an Algorithm
1. Efficiency.
Time efficiency, indicating how fast the algorithm runs,
Space efficiency, indicating how much extra memory it uses.
2. simplicity.
An algorithm should be precisely defined and investigated with mathematical
expressions.
Simpler algorithms are easier to understand and easier to program.
Simple algorithms usually contain fewer bugs.
Coding an Algorithm
Most algorithms are destined to be ultimately implemented as computer programs.
Programming an algorithm presents both a peril and an opportunity.
A working program provides an additional opportunity in allowing an empiricalanalysis
of the underlying algorithm. Such an analysis is based on timing the program on several
inputs and then analysing the results obtained.
Algorithm Analysis
Time Complexity: The time complexity of an algorithm quantifies the amount of time
taken by an algorithm to run as a function of the length of the input. Note that the time to
run is a function of the length of the input and not the actual execution time of the machine
on which the algorithm is running on.
Definition:
The valid algorithm takes a finite amount of time for execution. The time required by the
algorithm to solve given problem is called time complexity of the algorithm. Time
complexity is very useful measure in algorithm analysis.
Example 1: Addition of two scalar variables.Algorithm ADD SCALAR(A, B)
//Description: Perform arithmetic addition of two numbers
//Input: Two scalar variables A and B
//Output: variable C, which holds the addition of A and BC <- A + B
return C
The addition of two scalar numbers requires one addition operation. the time
9
Course Code/Title:CS3302/Design Analysis of Algorithms
The space complexity of an algorithm quantifies the amount of space taken by an algorithm
to run as a function of the length of the input. Consider an example: Suppose a problem to
find the frequency of array elements.
It is the amount of memory needed for the completion of an algorithm. To estimate the
(1) A fixed part: It is independent of the input size. It includes memory for instructions
(code), constants, variables, etc.
(2) A variable part: It is dependent on the input size. It includes memory for recursion
stack, referenced variables, etc.
10
Course Code/Title:CS3302/Design Analysis of Algorithms
1. Big O Notation
Big-O notation represents the upper bound of the running time of an algorithm.
Therefore, it gives the worst-case complexity of an algorithm. By using big O-
notation, we can asymptotically limit the expansion of a running time to a range of
constant factors above and below. It is a model for quantifying algorithm performance.
2. Omega Notation
Omega notation represents the lower bound of the running time of an
algorithm. Thus, it provides the best-case complexity of an algorithm.
The execution time serves as a lower bound on the algorithm’s time complexity. It is
defined as the condition that allows an algorithm to complete statement executionin the
shortest amount of time.
11
Course Code/Title:CS3302/Design Analysis of Algorithms
3. Theta Notation
Theta notation encloses the function from above and below. Since it represents the
upper and the lower bound of the running time of an algorithm, it is used for analyzing the
average-case complexity of an algorithm. The execution time serves as both a lower and
upper bound on the algorithm’s time complexity. It exists as both, the most, and least
boundaries for a given input value.
Mathematical Representation:
Θ (g(n)) = {f(n): there exist positive constants c1, c2 and n0 such that 0 ≤ c1 * g(n)
≤ f(n) ≤ c2 * g(n) for all n ≥ n0}
12
Course Code/Title:CS3302/Design Analysis of Algorithms
Measure of Complexity:
The complexity of an algorithm can be measured in three ways:
1. Time Complexity
The time complexity of an algorithm is defined as the amount of time taken by an
algorithm to run as a function of the length of the input. Note that the time to run is a
function of the length of the input and not the actual execution time of the machine on
which the algorithm is running on
To estimate the time complexity, we need to consider the cost of each fundamental
instruction and the number of times the instruction is executed.
T(n) = t(statement1) + t(statement2) + ... + t(statementN); Overall, T(n)= O(1), which means
constant complexity.
13
Course Code/Title:CS3302/Design Analysis of Algorithms
For any loop, we find out the runtime of the block inside them and multiplyit by
the number of times the program will repeat the loop.
for (int i = 0; i < n; i++) {
cout << “GeeksForGeeks” << endl;
}
For the above example, the loop will execute n times, and it will print
“GeeksForGeeks” N number of times. so the time taken to run this program is:
For 2D arrays, we would have nested loop concepts, which means a loop
inside a loop.
for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) {
cout << “GeeksForGeeks” << endl;
}
}
For the above example, the cout statement will execute n*m times, and it will
print “GeeksForGeeks” N*M number of times. so the time taken to run this programis:
2. Space Complexity :
The amount of memory required by the algorithm to solve a given problem is
called the space complexity of the algorithm. Problem-solving using a computer
14
Course Code/Title:CS3302/Design Analysis of Algorithms
requires memory to hold temporary data or final result while the program is in execution.
15
Course Code/Title:CS3302/Design Analysis of Algorithms
}
int pairSum(int x, int y){return x + y;
}
There will be roughly O(n) calls to pairSum. However, those calls do not
exist simultaneously on the call stack, so you only need O(1) space.
3. Auxiliary Space :
The temporary space needed for the use of an algorithm is referred to as auxiliary
space. Like temporary arrays, pointers, etc.
It is preferable to make use of Auxiliary Space when comparing things like sorting
algorithms. For example, sorting algorithms take O(n) space, as there is an input array to
sort. but the auxiliary space is O(1) in that case.
Time Complexity:
The valid algorithm takes a finite amount of time for execution. The time required
by the algorithm to solve given problem is called time complexity of the algorithm. Time
complexity is very useful measure in algorithm analysis. It is the time needed for the
completion of an algorithm. To estimate the time complexity, we need to consider the cost of
each fundamental instruction and the number of times the instruction is executed.
16
Course Code/Title:CS3302/Design Analysis of Algorithms
for(int i = 0;i < n;i++) for(int j = 0;j < n;j++) if(i!=j && a[i]+a[j] == z)
return truereturn false
Assuming that each of the operations in the computer takes approximately constant
time, let it be c. The number of lines of code executed actually depends onthe value of Z.
During analyses of the algorithm, mostly the worst-case scenario is considered, i.e., when
there is no pair of elements with sum equals Z. In the worst case,
N*c operations are required for input.The outer loop i loop runs N times.
For each i, the inner loop j loop runs N times.
So total execution time is N*c + N*N*c + c. Now ignore the lower order terms since the
lower order terms are relatively insignificant for large input, therefore onlythe highest order
term is taken (without constant) which is N*N in this case. Different notations are used to
describe the limiting behavior of a
function, but since the worst case is taken so big-O notation will be used torepresent the time
complexity.
Hence, the time complexity is O(N2) for the above algorithm. Note that the time
complexity is solely based on the number of elements in array A i.e the input length, so if
the length of the array will increase the time of execution will also increase.
Order of growth is how the time of execution depends on the length of the input. In
the above example, it is clearly evident that the time of execution quadratically depends on
the length of the array. Order of growth will help to compute the running time with ease.
Some general time complexities are listed below with the input range for which they
are accepted in competitive programming:
17
Course Code/Title:CS3302/Design Analysis of Algorithms
Recursion, manipulation
15- O(2N *
18 N) backtracking,
and
bit
Recursion, manipulation
18- O(2N *
22 N) backtracking,
and
bit
18
Course Code/Title:CS3302/Design Analysis of Algorithms
Sorting,Conquer a
1M O(N* log n
N) Binary d
Search,
Divide
19
Course Code/Title:CS3302/Design Analysis of Algorithms
Space Complexity:
Problem-solving using computer requires memory to hold temporary data or final
result while the program is in execution. The amount of memory required by the algorithm to
solve given problem is called space complexity of the algorithm.
It is the amount of memory needed for the completion of an algorithm.To estimate the memory
(1) A fixed part: It is independent of the input size. It includes memory for instructions
(code), constants, variables, etc.
(2) A variable part: It is dependent on the input size. It includes memory forrecursion
stack, referenced variables, etc.
20
Course Code/Title:CS3302/Design Analysis of Algorithms
Asymptotic Notations:
21
Course Code/Title:CS3302/Design Analysis of Algorithms
Theta (Average Case) You add the running times for each possible input
combination and take the average in the average case.
Let g and f be the function from the set of natural numbers to itself. The function f
is said to be Θ(g), if there are constants c1, c2 > 0 and a natural number n0 such that c1*
g(n) ≤ f(n) ≤ c2 * g(n) for all n ≥ n0
The above expression can be described as if f(n) is theta of g(n), then the value f(n) is
always between c1 * g(n) and c2 * g(n) for large values of n (n ≥ n0). The definition of
theta also requires that f(n) must be non-negative for values of n greaterthan n0.
The execution time serves as both a lower and upper bound on the algorithm’stime
complexity.
It exist as both, most, and least boundaries for a given input value.
A simple way to get the Theta notation of an expression is to drop low-order terms
and ignore leading constants. For example, Consider the expression 3n3 + 6n2
+ 6000 = Θ(n3), the dropping lower order terms is always fine because there will always
be a number(n) after which Θ(n3) has higher values than Θ(n2) irrespective of the constants
involved. For a given function g(n), we denote Θ(g(n)) is followingset of functions.
Examples :
22
Course Code/Title:CS3302/Design Analysis of Algorithms
For example, Consider the case of Insertion Sort. It takes linear time in the best case
and quadratic time in the worst case. We can safely say that the time complexity of the
Insertion sort is O(n2).
Note: O(n2) also covers linear time.
Note: Here, U represents union, we can write it in these manner because Oprovides
exact or upper bounds .
The execution time serves as a lower bound on the algorithm’s time complexity.
23
Course Code/Title:CS3302/Design Analysis of Algorithms
Let g and f be the function from the set of natural numbers to itself. The function f
is said to be Ω(g), if there is a constant c > 0 and a natural number n0 suchthat c*g(n) ≤ f(n)
for all n ≥ n0
Let us consider the same Insertion sort example here. The time complexity of
Insertion Sort can be written as Ω(n), but it is not very useful information about insertion
sort, as we are generally interested in worst-case and sometimes in the average case.
Examples :
Note: Here, U represents union, we can write it in these manner because Ωprovides exact
or lower bounds.
1. General Properties:
If f(n) is O(g(n)) then a*f(n) is also O(g(n)), where a is a constant.Example:
If f(n) is Θ(g(n)) then a*f(n) is also Θ(g(n)), where a is a constant. If f(n) is Ω (g(n)) then
a*f(n) is also Ω (g(n)), where a is a constant.
2. Transitive Properties:
If f(n) is O(g(n)) and g(n) is O(h(n)) then f(n) = O(h(n)).
f(n) = O(g(n)) and g(n) = O(h(n)) ⇒ f(n) = O(h(n))Example:
24
Course Code/Title:CS3302/Design Analysis of Algorithms
3. Reflexive Properties:
Reflexive properties are always easy to understand after transitive.
If f(n) is given then f(n) is O(f(n)). Since MAXIMUM VALUE OF f(n) will be f(n)ITSELF!
f(n) = O(f(n))
Hence x = f(n) and y = O(f(n) tie themselves in reflexive relation always.Example:
If f(n) is given then f(n) is Θ(f(n)).If f(n) is given then f(n) is Ω (f(n)).
4. Symmetric Properties:
If f(n) is Θ(g(n)) then g(n) is Θ(f(n)).
f(n) = Θ(g(n)) if and only if g(n) = Θ(f(n))Example:
If(n) = n , g(n) = n²
then n is O(n²) and n² is Ω (n)
25
Course Code/Title:CS3302/Design Analysis of Algorithms
Example:
f(n) = n i.e O(n)
d(n) = n² i.e O(n²)
then f(n) * d(n) = n * n² = n³ i.e O(n³) Note: If f(n) = O(g(n)) then g(n) = Ω(f(n))
26
Course Code/Title:CS3302/Design Analysis of Algorithms
Examples:
1. Linear search algorithm:
// C++ implementation of the approach#include <bits/stdc++.h>
using namespace std;
27
Course Code/Title:CS3302/Design Analysis of Algorithms
{
int arr[] = { 1, 10, 30, 15 };
int x = 30;
int n = sizeof(arr) / sizeof(arr[0]);
// Function call
cout << x << " is present at index "
<< search(arr, n, x);
return 0;
}
Output
30 is present at index 2
Best Case: O(1), This will take place if the element to be searched is on the first index of
the given list. So, the number of comparisons, in this case, is 1.
Average Case: O(n), This will take place if the element to be searched is on themiddle
index of the given list.
Worst Case: O(n), This will take place if:
The element to be searched is on the last index
The element to be searched is not present on the list
Advantages:
● This technique allows developers to understand the performance of algorithms under different
scenarios, which can help in making informed decisions aboutwhich algorithm to use for a
specific task.
● Worst case analysis provides a guarantee on the upper bound of the running time of an
algorithm, which can help in designing reliable and efficient algorithms.
● Average case analysis provides a more realistic estimate of the running time of an
algorithm, which can be useful in real-world scenarios.
Disadvantages:
● This technique can be time-consuming and requires a good understanding of the algorithm
being analyzed.
● Worst case analysis does not provide any information about the typical running time of an
algorithm, which can be a disadvantage in real-world scenarios.
28
Course Code/Title:CS3302/Design Analysis of Algorithms
● Average case analysis requires knowledge of the probability distribution ofinput data,
which may not always be available.
Important points:
● The worst case analysis of an algorithm provides an upper bound on therunning
time of the algorithm for any input size.
● The average case analysis of an algorithm provides an estimate of therunning time
of the algorithm for a random input.
● The best case analysis of an algorithm provides a lower bound on therunning time
of the algorithm for any input size.
● The big O notation is commonly used to express the worst case running time of an
algorithm.
● Different algorithms may have different best, average, and worst caserunning times.
Recurrence Relation
A recurrence is an equation or inequality that describes a function in terms ofits
values on smaller inputs. To solve a Recurrence Relation means to obtain a function
defined on the natural numbers that satisfy the recurrence.
1. Substitution Method:
The Substitution Method Consists of two main steps:
● Guess the Solution.
● Use the mathematical induction to find the boundary condition andshows that the
guess is correct.
29
Course Code/Title:CS3302/Design Analysis of Algorithms
T (n) ≤c logn.
Put this in given Recurrence Equation.
Solution:
T (n) = 2T (n-1)
= 2[2T (n-2)] = 22T (n-2)
= 4[2T (n-3)] = 23T (n-3)
= 8[2T (n-4)] = 24T (n-4) (Eq.1)
30
Course Code/Title:CS3302/Design Analysis of Algorithms
T (n) = 2i T (n-i)
Put n-i=1 or i= n-1 in (Eq.1)T (n) = 2n-1 T (1)
= 2n-1 .1 {T (1) =1 ........ given}
= 2n-1
Example2: Consider the Recurrence
T (n) = T (n-1) +1
= (T (n-2) +1) +1 = (T (n-3) +1) +1+1
= T (n-4) +4 = T (n-5) +1+4
= T (n-5) +5= T (n-k) + k
Where k = n-1
T (n-k) = T (1) = θ (1)
T (n) = θ (1) + (n-1) = 1+n-1=n= θ (n).
Tree Structure
Each node in a recursion tree represents a particular recursive call. The initialcall
is depicted at the top, with subsequent calls branching out beneath it. The tree grows
downward, forming a hierarchical structure. The branching factor
31
Course Code/Title:CS3302/Design Analysis of Algorithms
of each node depends on the number of recursive calls made within the function.
Additionally, the depth of the tree corresponds to the number of recursive calls before
reaching the base case.
Base Case
The base case serves as the termination condition for a recursive function. It
defines the point at which the recursion stops and the function starts returning values. In a
recursion tree, the nodes representing the base case are usually depicted as leafnodes, as
they do not result in further recursive calls.
Recursive Calls
The child nodes in a recursion tree represent the recursive calls made within the
function. Each child node corresponds to a separate recursive call, resulting in the creation
of new sub problems. The values or parameters passed to these recursive calls may differ,
leading to variations in the sub problems' characteristics.
Execution Flow:
Traversing a recursion tree provides insights into the execution flow of a recursive
function. Starting from the initial call at the root node, we follow the branches to reach
subsequent calls until we encounter the base case. As the base cases are reached, the
recursive calls start to return, and their respective nodes in thetree are marked with the
returned values. The traversal continues until the entire treehas been traversed.
Introduction
Think of a program that determines a number's factorial. This function takes a
number N as an input and returns the factorial of N as a result. This function's pseudo-
code will resemble,
// find factorial of a number factorial(n) {
// Base case
if n is less than 2: // Factorial of 0, 1 is 1 return n
32
Course Code/Title:CS3302/Design Analysis of Algorithms
// Recursive step
return n * factorial(n-1); // Factorial of 5 => 5 * Factorial(4)...
}
Factorial(5) [ 120 ]
|
5 * Factorial(4) ==> 120
|
4. * Factorial(3) ==> 24
|
3 * Factorial(2) ==> 6
|
2 * Factorial(1) ==> 2
|1
*/
Recursion is exemplified by the function that was previously mentioned. We
are invoking a function to determine a number's factorial. Then, given a lesser valueof
the same number, this function calls itself. This continues until we reach the basiccase,
in which there are no more function calls.
Recursion is a technique for handling complicated issues when the outcome is
dependent on the outcomes of smaller instances of the same issue.
If we think about functions, a function is said to be recursive if it keeps calling itself
until it reaches the base case.
Any recursive function has two primary components: the base case and the
recursive step. We stop going to the recursive phase once we reach the basic case. To
prevent endless recursion, base cases must be properly defined and are crucial. The
definition of infinite recursion is a recursion that never reaches the base case. If a
program never reaches the base case, stack overflow will continue to occur.
Recursion Types
Generally speaking, there are two different forms of recursion:
1. Linear Recursion
2. Tree Recursion
Linear Recursion:
33
Course Code/Title:CS3302/Design Analysis of Algorithms
A function that calls itself just once each time it executes is said to be linearly
recursive. A nice illustration of linear recursion is the factorial function. The name "linear
recursion" refers to the fact that a linearly recursive function takes a linear amount of time
to execute.
Tree Recursion
When you make a recursive call in your recursive case more than once, it is referred
to as tree recursion. An effective illustration of Tree recursion is the fibonacci sequence.
Tree recursive functions operate in exponential time; they are not linear in their temporal
complexity.
34
Course Code/Title:CS3302/Design Analysis of Algorithms
35
Course Code/Title:CS3302/Design Analysis of Algorithms
For instance, since the recurrence relation for binary search is T(N) = T(N/2)
+ 1, we know that each iteration of binary search results in a search space that is cut in half.
Once the outcome is determined, we exit the function. The recurrence relation has +1 added
because this is a constant time operation.
The recurrence relation T(n) = 2T(n/2) + Kn is one to consider. Kn denotes the
amount of time required to combine the answers to n/2-dimensional sub problems.
Let's depict the recursion tree for the aforementioned recurrence relation.
1. The magnitude of the problem at each level is all that matters for determining the
value of a node. The issue size is n at level 0, n/2 at level 1, n/2 at level 2, and so on.
2. In general, we define the height of the tree as equal to log (n), where n is the size of
the issue, and the height of this recursion tree is equal to the number of levels in the tree.
This is true because, as we just established, the divide-and-conquer strategy is used by
recurrence relations to solve problems, and getting from issue size n to problem size 1 simply
requires taking log (n) steps.
Consider the value of N = 16, for instance. If we are permitted to divide N by2 at each
step, how many steps are required to get N = 1? Considering that we
36
Course Code/Title:CS3302/Design Analysis of Algorithms
are dividing by two at each step, the correct answer is 4, which is the value of log(16)base
2.
log(16) base 2
log(2^4) base 2
3. At each level, the second term in the recurrence is regarded as the root.
Although the word "tree" appears in the name of this strategy, you don't need to bean
expert on trees to comprehend it.
Example
Solution
A problem size n is divided into two sub-problems each of size n/2. The cost of
combining the solutions to these sub-problems is K.
Each problem size of n/2 is divided into two sub-problems each of size n/4 and soon.
37
Course Code/Title:CS3302/Design Analysis of Algorithms
At the last level, the sub-problem size will be reduced to 1. In other words, we finally hit
the base case.
Let's follow the steps to solve this recurrence relation, Step 1: Draw the
Recursion Tree
Since we know that when we continuously divide a number by 2, there comes a time
when this number is reduced to 1. Same as with the problem size N, suppose after K
divisions by 2, N becomes equal to 1, which implies, (n / 2^k) = 1
Here n / 2^k is the problem size at the last level and it is always equal to 1.
Now we can easily calculate the value of k from the above expression by taking log() to
both sides. Below is a more clear derivation,
n = 2^k
38
Course Code/Title:CS3302/Design Analysis of Algorithms
Let's first determine the number of nodes in the last level. From the recursion tree,we
can deduce this
Level-0 have 1 (2^0) node Level-1 have 2 (2^1) nodesLevel-2 have 4 (2^2) nodes
Level-3 have 8 (2^3) nodes
So the level log(n) should have 2^(log(n)) nodes i.e. n nodes.Step 5: Sum up the cost
39
Course Code/Title:CS3302/Design Analysis of Algorithms
The Lower Bound is very important for any algorithm. Once we calculated it,
then we can compare it with the actual complexity of the algorithm and if their orderis
the same then we can declare our algorithm as optimal. So in this section, we willbe
discussing techniques for finding the lower bound of an algorithm.
Note that our main motive is to get an optimal algorithm, which is the one
having its Upper Bound the Same as its Lower Bound (U(n)=L(n)). Merge Sort is a
common example of an optimal algorithm.
Input: For 2 matrices we will have 2n2 inputs Output: 1 matrix of order n x n, i.e., n2
outputs
In the above example, it’s easily predictable that the lower bound is O(n2).
Computational Model –
The method is for all those algorithms that are comparison-based. For example,
in sorting, we have to compare the elements of the list among themselves and then sort
them accordingly. Similar is the case with searching and thus we can implement the
same in this case. Now we will look at some examples to understandits usage.
Ordered Searching –
It is a type of searching in which the list is already sorted.Example-1: Linear search
Explanation –
40
Course Code/Title:CS3302/Design Analysis of Algorithms
In linear search, we compare the key with the first element if it does not matchwe
compare it with the second element, and so on till we check against the nth element. Else
we will end up with a failure.
Calculating the lower bound: The max no of comparisons is n. Let there be k levels
in the tree.
No. of nodes will be 2k-1
The upper bound of no of nodes in any comparison-based search of an element in the
list of size n will be n as there are a maximum of n comparisons in worst casescenario 2k-
1
Each level will take 1 comparison thus no. of comparisons k≥|log2n|
Thus the lower bound of any comparison-based search from a list of n elements
cannot be less than log(n). Therefore we can say that Binary Search is optimal as its
complexity is Θ(log n).
Sorting –
The diagram below is an example of a tree formed in sorting combinationswith 3
elements.
41
Course Code/Title:CS3302/Design Analysis of Algorithms
Explanation –
For n elements, we have a total of n! combinations (leaf nodes). (Refer to the
diagram the total combinations are 3! or 6) also, it is clear that the tree formed is a
binary tree. Each level in the diagram indicates a comparison. Let there be k levels
=> 2k is the total number of leaf nodes in a full binary tree thus in this case we have
n!≤2k.
42
Course Code/Title:CS3302/Design Analysis of Algorithms
The type of program built without any loops or control structures is calledthe
Straight Line Program. For example,
#include <iostream>
// Function to sum two numbers without using loops or control structuresint Sum(int a,
int b) {
int c = a + b;return c;
}
int main() {
// Example usageint num1 = 5;
int num2 = 7;
std::cout << "The sum of " << num1 << " and " << num2 << " is: " << result <<
std::endl;
return 0;
}
Output
The sum of 5 and 7 is: 12
Algebraic Problem –
Problems related to algebra like solving equations inequalities etc. come under
algebraic problems. For example, solving equation ax2+bx+c with simple
programming.
#include <iostream>
// 1 assignmentv = v + b;
43
Course Code/Title:CS3302/Design Analysis of Algorithms
// 1 assignmentv = v * x;
int main() {
// Example usage
int result = Algo_Sol(2, 3, 4, 5);
std::cout << "Result: " << result << std::endl;
return 0;
}
Output Result: 69
#include <iostream>
#include <vector> // Include vector header for using vectors
// Loop from 1 to n
for (int i = 1; i <= n; ++i) {p *= x;
44
Course Code/Title:CS3302/Design Analysis of Algorithms
return p;
}
// Function to evaluate the polynomial with coefficients A, value x, and degree n int
polynomial(std::vector<int>& A, int x, int n) {
int v = 0;
return v;
}
int main() {
// Example usage:
std::vector<int> A = {2, 3, 4}; // Coefficients of the polynomialint x = 5; // Value of x
int n = A.size() - 1; // Degree of the polynomial
return 0;
}
45
Course Code/Title:CS3302/Design Analysis of Algorithms
Theorem: To prove that the optimal algo of solving a n degree polynomial is O(n) Proof: The
best solution for reducing the algo is to make this problem less complexby dividing the polynomial
into several straight-line problems.
#include <iostream>
return v;
}
int main() {
// Example usage
int coefficients[] = {2, -1, 3}; // Coefficients of the polynomial 2x^2 - x + 3int degree = 2;
// Degree of the polynomial
int x_value = 4; // Value of x
std::cout << "Result of the polynomial evaluation: " << result << std::endl;
46
Course Code/Title:CS3302/Design Analysis of Algorithms
return 0;
}
Output
Result of the polynomial evaluation: 184
The complexity of this code is O(n). This way of solving such equations is called
Horner’s method. Here is where lower bound theory works and gives the optimum algorithm’s
complexity as O(n).
Advantages:
● Provides a clear understanding of the range of possible values for a quantity,which can be
useful in decision-making.
● Helps to identify the optimal value within the range of possible values,which can lead
to more efficient and effective solutions to problems.
● Can be used to prove the existence of solutions to optimization problems.
● Provides a theoretical framework for analyzing and solving a wide range ofmathematical
problems.
Disadvantages:
● May not always provide a precise solution to optimization problems, as the optimal value
may not be within the range of possible values determined by the lower and upper bounds.
● Can be computationally intensive, especially for complex optimization problems with
many constraints.
● May be limited by the accuracy of the data used to determine the lower and upper bounds.
● Requires a strong mathematical background to use effectively.
Searching
Searching is the fundamental process of locating a specific element or item within
a collection of data. This collection of data can take various forms, such as arrays, lists,
trees, or other structured representations. The primary objective of searching is to
determine whether the desired element exists within the data, and if so, to identify its
precise location or retrieve it. It plays an important role in various
47
Course Code/Title:CS3302/Design Analysis of Algorithms
Searching terminologies:
Target Element:
In searching, there is always a specific target element or item that you want tofind
within the data collection. This target could be a value, a record, a key, or any other data
entity of interest.
Search Space:
The search space refers to the entire collection of data within which you are looking
for the target element. Depending on the data structure used, the search space may vary in
size and organization.
Complexity:
Searching can have different levels of complexity depending on the data structure
and the algorithm used. The complexity is often measured in terms of time and space
requirements.
Applications of Searching:
Searching algorithms have numerous applications across various fields. Here are
some common applications:
1. Information Retrieval: Search engines like Google, Bing, and Yahoo use sophisticated
searching algorithms to retrieve relevant information from vast amounts of data on the web.
2. Database Systems: Searching is fundamental in database systems for retrieving specific
data records based on user queries, improving efficiency indata retrieval.
3. E-commerce: Searching is crucial in e-commerce platforms for users to find products
quickly based on their preferences, specifications, or keywords.
4. Networking: In networking, searching algorithms are used for routing packets
48
Course Code/Title:CS3302/Design Analysis of Algorithms
efficiently through networks, finding optimal paths, and managing network resources.
5. Artificial Intelligence: Searching algorithms play a vital role in AI applications, such as
problem-solving, game playing (e.g., chess), and decision-making processes
6. Pattern Recognition: Searching algorithms are used in pattern matching tasks,such as
image recognition, speech recognition, and handwriting recognition.
Algorithm:
Start: Begin at the first element of the collection of elements. Compare: Compare the
current element with the desired element.
Found: If the current element is equal to the desired element, return true or index tothe
current element.
Move: Otherwise, move to the next element in the collection. Repeat: Repeat steps 2-4
until we have reached the end of collection.
Not found: If the end of the collection is reached without finding the desired
element, return that the desired element is not in the array.
Working:
● Every element is considered as a potential match for the key and checked forthe same.
● If any element is found equal to the key, the search is successful and theindex of
that element is returned.
● If no element is found equal to the key, the search yields “No match found”.
For example: Consider the array arr[] = {10, 50, 30, 70, 80, 20, 90, 40} and
key = 30
Step 1: Start from the first element (index 0) and compare key with each element
(arr[i]).
Comparing key with first element arr[0]. SInce not equal, the iterator moves to thenext
element as a potential match.
49
Course Code/Title:CS3302/Design Analysis of Algorithms
Comparing key with next element arr[1]. SInce not equal, the iterator moves to the next
element as a potential match.
Step 2: Now when comparing arr[2] with key, the value matches. So the Linear Search
Algorithm will yield a successful message and return the index of the element when key is
found (here 2).
Time Complexity:
Best Case: In the best case, the key might be present at the first index. So the best case
complexity is O(1)
Worst Case: In the worst case, the key might be present at the last index i.e., opposite to the
end from which the search has started in the list. So the worst-case complexityis O(N)
where N is the size of the list.
Average Case: O(N)
Auxiliary Space: O(1) as except for the variable to iterate through the list, no other
variable is used.
50
Course Code/Title:CS3302/Design Analysis of Algorithms
2. Small Data Sets: Linear Search is preferred over binary search when we havesmall data
sets with
3. Searching Linked Lists: In linked list implementations, linear search is commonly used
to find elements within the list. Each node is checked sequentially until the desired
element is found.
4. Simple Implementation: Linear Search is much easier to understand and implement as
compared to Binary Search or Ternary Search.
51
Course Code/Title:CS3302/Design Analysis of Algorithms
● In this algorithm, Divide the search space into two halves by finding themiddle
index “mid”.
● Compare the middle element of the search space with the key.
● If the key is found at middle element, the process is terminated.
● If the key is not found at middle element, choose which half will be used asthe next
search space.
● If the key is smaller than the middle element, then the left side is used fornext search.
● If the key is larger than the middle element, then the right side is used fornext search.
● This process is continued until the key is found or the total search space isexhausted.
First Step: Calculate the mid and compare the mid element with the key. If the key is
less than mid element, move to left and if it is greater than the mid then move search
space to the right.
Key (i.e., 23) is greater than current mid element (i.e., 16). The search space moves to
the right.
Key is less than the current mid 56. The search space moves to the left.
52
Course Code/Title:CS3302/Design Analysis of Algorithms
If the key matches the value of the mid element, the element is found and stop search.
The Binary Search Algorithm can be implemented in the following two ways
1. Iterative Binary Search Algorithm
2. Recursive Binary Search Algorithm
53
Course Code/Title:CS3302/Design Analysis of Algorithms
return mid;
54
Course Code/Title:CS3302/Design Analysis of Algorithms
Output
Element is present at index 3
Complexity Analysis of Binary Search Algorithm:
Time Complexity:
Best Case: O(1) Average Case: O(log N)Worst Case: O(log N)
Auxiliary Space: O(1), If the recursive call stack is considered then the auxiliaryspace
will be O(logN).
55
Course Code/Title:CS3302/Design Analysis of Algorithms
Pattern Searching:
Pattern searching involves searching for a specific pattern or sequence of
elements within a given data structure. This technique is commonly used in string
matching algorithms to find occurrences of a particular pattern within a text or a larger
string. By using various algorithms like the Knuth-Morris-Pratt (KMP)algorithm or the
Rabin-Karp algorithm, pattern searching plays a crucial role in tasks such as text processing,
data retrieval, and computational biology.
56
Course Code/Title:CS3302/Design Analysis of Algorithms
Input: text = “THIS IS A TEST TEXT”, pattern = “TEST”Output: Pattern found at index
10
57
Course Code/Title:CS3302/Design Analysis of Algorithms
Slide the pattern over text one by one and check for a match. If a match is found,then
slide by 1 again to check for subsequent matches.
#include <iostream>#include <string> using namespace std;
58
Course Code/Title:CS3302/Design Analysis of Algorithms
59
Course Code/Title:CS3302/Design Analysis of Algorithms
W The pattern is found at the very beginning of the text (or very early
h
e The algorithm will perform a constant number of comparisons, typically on
n
the order of O(n) comparisons, where n is the length of the pattern.Worst Case: O(n2)
When the pattern doesn’t appear in the text at all or appears only at the very
end.
The algorithm will perform O((n-m+1)*m) comparisons, where n is the
length of the text and m is the length of the pattern.
In the worst case, for each position in the text, the algorithm may need to compare the entire
pattern against the text.
Examples:
60
Course Code/Title:CS3302/Design Analysis of Algorithms
The worst case complexity of the Naive algorithm is O(m(n-m+1)). The timecomplexity
of the KMP algorithm is O(n+m) in the worst case.
The Naive pattern-searching algorithm doesn’t work well in cases where we see
many matching characters followed by a mismatching character.
Examples:
The KMP matching algorithm uses degenerating property (pattern having thesame
sub-patterns appearing more than once in the pattern) of the pattern and improves the worst-
case complexity to O(n+m).
The basic idea behind KMP’s algorithm is: whenever we detect a mismatch (after
some matches), we already know some of the characters in the text of the nextwindow. We
take advantage of this information to avoid matching the characters that we know will
anyway match.
61
Course Code/Title:CS3302/Design Analysis of Algorithms
Matching Overview
txt = “AAAAABAAABA”
pat = “AAAA” [Initial position]
We find a match. This is same as Naive String Matching.
In the next step, we compare next window of txt with pat.txt = “AAAAABAAABA”
pat = “AAAA” [Pattern shifted one position]
This is where KMP does optimization over Naive. In this second window, weonly
compare fourth A of pattern with fourth character of current window of text to decide
whether current window matches or not. Since we know first three characterswill anyway
match, we skipped matching first three characters.
Need of Preprocessing?
An important question arises from the above explanation, how to know how many
characters to be skipped. To know this, we pre-process pattern and prepare aninteger array
lps[] that tells us the count of characters to be skipped
Preprocessing Overview:
KMP algorithm preprocesses pat[] and constructs an auxiliary lps[] of size m(same
as the size of the pattern) which is used to skip characters while matching.
Name lps indicates the longest proper prefix which is also a suffix. A proper prefix
is a prefix with a whole string not allowed. For example, prefixes of “ABC” are “”, “A”,
“AB” and “ABC”. Proper prefixes are “”, “A” and “AB”. Suffixes of the string are “”, “C”,
“BC”, and “ABC”.
We search for lps in subpatterns. More clearly we focus on sub-strings of patterns
that are both prefix and suffix.
For each sub-pattern pat[0..i] where i = 0 to m-1, lps[i] stores the length of the
maximum matching proper prefix which is also a suffix of the sub-pattern pat[0..i].
lps[i] = the longest proper prefix of pat[0..i] which is also a suffix of pat[0..i].
62
Course Code/Title:CS3302/Design Analysis of Algorithms
Note: lps[i] could also be defined as the longest prefix which is also a proper suffix. We
need to use it properly in one place to make sure that the whole substring is not
considered.
Preprocessing Algorithm:
In the preprocessing part, We calculate values in lps[]. To do that, we keep track
of the length of the longest prefix suffix value (we use len variable for this purpose) for
the previous index
We initialize lps[0] and len as 0.
If pat[len] and pat[i] match, we increment len by 1 and assign the incremented
value to lps[i].
If pat[i] and pat[len] do not match and len is not 0, we update len to lps[len-
1]
pat[] = “AAACAAAA”
=> len = 0, i = 0:
63
Course Code/Title:CS3302/Design Analysis of Algorithms
Since pat[len] and pat[i] do not match, and len > 0,Set len = lps[len-1] = lps[1] = 1
=> len = 1, i = 3:
Since pat[len] and pat[i] do not match and len > 0,len = lps[len-1] = lps[0] = 0
=> len = 0, i = 3:
Since pat[len] and pat[i] do not match and len = 0,Set lps[3] = 0 and i = 4
=> len = 0, i = 4:
Since pat[len] and pat[i] do not match and len > 0,Set len = lps[len-1] = lps[2] = 2
=> len = 2, i = 7:
64
Course Code/Title:CS3302/Design Analysis of Algorithms
How to use lps[] to decide the next positions (or to know the number of characters to be
skipped)?
-> i = 4, j = 4: Since j = M, print pattern found and reset j, j = lps[j-1] = lps[3] = 3Here
65
Course Code/Title:CS3302/Design Analysis of Algorithms
characters of this window. Value of lps[j-1] (in above step) gave us index of nextcharacter
to match.
-> i = 5, j = 4: Since j == M, print pattern found and reset j, j = lps[j-1] = lps[3] = 3Again
unlike Naive algorithm, we do not match first three characters of this window. Value of lps[j-
1] (in above step) gave us index of next character to match.
-> i = 5, j = 3: txt[i] and pat[j] do NOT match and j > 0, change only j. j = lps[j-1]
= lps[2] = 2
-> i = 5, j = 2: txt[i] and pat[j] do NOT match and j > 0, change only j. j = lps[j-1]
= lps[1] = 1
-> i = 5, j = 1: txt[i] and pat[j] do NOT match and j > 0, change only j. j = lps[j-1]
= lps[0] = 0
We continue this way till there are sufficient characters in the text to be comparedwith
the characters in the pattern…
#include <bits/stdc++.h>
66
Course Code/Title:CS3302/Design Analysis of Algorithms
int N = strlen(txt);
int i = 0; // index for txt[] int j = 0; // index for pat[] while ((N - i) >= (M - j)) {
if (pat[j] == txt[i]) {j++;
i++;
}
if (j == M) {
printf("Found pattern at index %d ", i - j);j = lps[j - 1];
}
67
Course Code/Title:CS3302/Design Analysis of Algorithms
68
Course Code/Title:CS3302/Design Analysis of Algorithms
Time Complexity: O(N+M) where N is the length of the text and M is the length ofthe
pattern to be found.
Auxiliary Space: O(M)
Examples:
In the Naive String Matching algorithm, we check whether every substring ofthe text
of the pattern’s size is equal to the pattern or not one by one.
Like the Naive Algorithm, the Rabin-Karp algorithm also check every substring.
But unlike the Naive algorithm, the Rabin Karp algorithm matches the hash value of the
pattern with the hash value of the current substring of text, and if the hash values match
then only it starts matching individual characters. So Rabin Karp algorithm needs to
calculate hash values for the following strings.
● Pattern itself
● All the substrings of the text of length m which is the size of pattern.
69
Course Code/Title:CS3302/Design Analysis of Algorithms
Here’s how the hash value is typically calculated in Rabin-Karp:Step 1: Choose a suitable
Select a prime number ‘p‘ as the modulus. This choice helps avoid overflow issuesand
ensures a good distribution of hash values.
Choose a base ‘b‘ (usually a prime number as well), which is often the size of thecharacter
set (e.g., 256 for ASCII characters).
Step 2: Initialize the hash value:
Start by calculating the hash value for the first substring of the text that is the same length
as the pattern.
Step 5: Update the hash value for each subsequent substring:
To slide the pattern one position to the right, you remove the contribution of theleftmost
character and add the contribution of the new character on the right.
The formula for updating the hash value when moving from position ‘i’ to ‘i+1’ is:hash =
(hash - (text[i - pattern_length] * (bpattern_length - 1)) % p) * b + text[i] Step 6: Compare
hash values:
When the hash value of a substring in the text matches the hash value of thepattern,
it’s a potential match.
If the hash values match, we should perform a character-by-character comparison to
confirm the match, as hash collisions can occur.
70
Course Code/Title:CS3302/Design Analysis of Algorithms
Step-by-step approach:
71
Course Code/Title:CS3302/Design Analysis of Algorithms
{
int M = strlen(pat);int N = strlen(txt);int i, j;
int p = 0; // hash value for patternint t = 0; // hash value for txt
int h = 1;
if (j == M)
cout << "Pattern found at index " << i
<< endl;
}
72
Course Code/Title:CS3302/Design Analysis of Algorithms
The average and best-case running time of the Rabin-Karp algorithm is O(n+m), but its worst-
case time is O(nm).
The worst case of the Rabin-Karp algorithm occurs when all characters of pattern and text are
the same as the hash values of all the substrings of T[] match with the hash value of P[].
73
Course Code/Title:CS3302/Design Analysis of Algorithms
74
Course Code/Title:CS3302/Design Analysis of Algorithms
A Spanning Tree is a tree which have V vertices and V-1 edges. All nodes in a spanning
tree are reachable from each other.
1. Prim’s Algorithm
2. Kruskal’s Algorithm
Prim’s Algorithm:
Prim's algorithm is a minimum spanning tree algorithm that takes a graph as input and
finds the subset of the edges of that graph which
Form a tree that includes every vertex
has the minimum sum of weights among all the trees that can be formed from the
graph.
It falls under a class of algorithms called greedy algorithms that find the local optimum in
the hopes of finding a global optimum.
We start from one vertex and keep adding edges with the lowest weight until we reach our
goal.
75
Course Code/Title:CS3302/Design Analysis of Algorithms
Choose a vertex
Choose the nearest edge not yet in the solution, if there are multiple choices, choose one
at random
76
Course Code/Title:CS3302/Design Analysis of Algorithms
The pseudocode for prim's algorithm shows how we create two sets of vertices U and
V-U. U contains the list of vertices that have been visited and V-U the list of vertices that
haven't. One by one, we move vertices from set V-U to set U by connecting the least weight
edge.
T=∅;
U={1};
while(U≠V)
Kruskal Algorithm:
Kruskal's algorithm is a minimum spanning tree algorithm that takes a graph as input and
finds the subset of the edges of that graph which
Form a tree that includes every vertex
Has the minimum sum of weights among all the trees that can be formed from the
graph
It falls under a class of algorithms called greedy algorithms that find the local optimum in
the hopes of finding a global optimum.
We start from the edges with the lowest weight and keep adding edges until we reach our
goal.
2. Take the edge with the lowest weight and add it to the spanning tree. If adding the
edge created acycle, then reject this edge.
77
Course Code/Title:CS3302/Design Analysis of Algorithms
Example of Kruskal'salgorithm:
Choose the edge with the least weight, if there are more than 1, choose anyone
Choose the next shortest edge that doesn't create a cycle and add it
Choose the next shortest edge that doesn't create a cycle and add it
78
Course Code/Title:CS3302/Design Analysis of Algorithms
KRUSKAL(G):
A =∅
For each vertex v ∈ G.V:
MAKE-SET(v)
For each edge(u,v) ∈ G.E ordered by increasing order by weight(u,v):
if FIND-SET(u) ≠ FIND-SET(v):
A=A 𝖴 {(u,v)}
UNION(u, v)
return A
The shortest path problem is about finding a path between vertices in a graph suchthat
thetotal sum of the edges weights is minimum.
Bellman Algorithm:
Bellman Ford algorithm helps us find the shortest path from a vertex to all other vertices
of a weighted graph. It is similar to Dijkstra's algorithm but it can work with graphs in which
edges can have negative weights.
By doing this repeatedly for all vertices, we can guarantee that the result is optimized.
79
Course Code/Title:CS3302/Design Analysis of Algorithms
80
Course Code/Title:CS3302/Design Analysis of Algorithms
We need to maintain the path distance of every vertex. We can store that in an array of
size v, where v is the number of vertices.
We also want to be able to get the shortest path, not only know the length of the shortest
path. For this, we map each vertex to the vertex that last updated its path length.
Once the algorithm is over, we can backtrack from the destination vertex to the source
vertex to find the path.
foreach vertex V in G
81
Course Code/Title:CS3302/Design Analysis of Algorithms
Time Complexity:
Dijkstra Algorithm:
Dijkstra's algorithm allows us to find the shortest path between any two vertices of a
graph.
It differs from the minimum spanning tree because the shortest distance between two
vertices might notinclude all the vertices of the graph.
Dijkstra's Algorithm works on the basis that any subpath B -> D of the hortest path A ->
D between vertices A and D is also the shortest path between vertices B and D.
82
Course Code/Title:CS3302/Design Analysis of Algorithms
Each subpath is the shortest path Djikstra used this property in the opposite direction i.e
we overestimate the distance of each vertex from the starting vertex.Then we visit each
node and its neighbors to find the shortest subpath to those neighbors.
The algorithm uses a greedy approach in the sense that we find the next best solution
hoping that the end result is the best solution for the whole problem.
Example of Dijkstra's algorithm:
It is easier to start with an example and then think about the algorithm.
Choose a starting vertex and assign infinity path values to all other devices
83
Course Code/Title:CS3302/Design Analysis of Algorithms
If the path length of the adjacent vertex is lesser than new path length, don't update it
After each iteration, we pick the unvisited vertex with the least path length. So we choose
84
Course Code/Title:CS3302/Design Analysis of Algorithms
5 before 7
Notice how the right most vertex has its path length updated twice
We need to maintain the path distance of every vertex. We can store that in an array of
size v, where v is thenumber of vertices.
We also want to be able to get the shortest path, not only know the length of the shortest
path. For this, we map each vertex to the vertex that last updated its path length.
Once the algorithm is over, we can backtrack from the destination vertex to the source
vertex to find the path.
A minimum priority queue can be used to efficiently receive the vertex with least path
distance.
functiondijkstra(G, S)
for each vertex V in G
distance[V] <- infinite
previous[V] <- NULL
If V!=S, add V to Priority Queue Q
distance[S] <- 0
85
Course Code/Title:CS3302/Design Analysis of Algorithms
distance[V]<-tempDistanceprevious[V] <- U
return distance[],previous[]
Floyd-Warshall Algorithm is an algorithm for finding the shortest path between all the
pairs of vertices in a weighted graph. This algorithm works for both the directed and
undirected weighted graphs. But, it does not work for the graphs with negative cycles
(where the sum of the edges in a cycle is negative).
A weighted graph is a graph in which each edge has a numerical value associated with
it. Floyd-Warhshall algorithm is also called as Floyd's algorithm, Roy-Floyd
algorithm, Roy-Warshallalgorithm, or WFI algorithm.
This algorithm follows the dynamic programming approach to find the shortest paths.
How Floyd-Warshall Algorithm Works?
Initial graph
Follow the steps below to find the shortest path between all the pairs of vertices.
1. Create a matrix A0 of dimension n*n where n is the number of vertices. The row
and the column are indexed as i and j respectively. i and j are the vertices of the
graph. Each cell A[i][j] is filled with the distance from the ith vertex to the jth vertex.
If there is no path from ith vertex to jth vertex, the cell is left as infinity.
86
Course Code/Title:CS3302/Design Analysis of Algorithms
Fill each cell with the distance between ith and jth vertex
2. Now, create a matrix A1 using matrix A0. The elements in the first column and the
first row are left as they are. The remaining cells are filled in the following way. Let
k be the intermediate vertex in the shortest path from source to destination.
That is, if the direct distance from the source to the destination is greater than the
path h the vertex k,then the cell is filled with A[i][k] + A[k][j].
For example:
For A1[2,4], the direct distance from vertex 2 to 4 is 4 and the sum of the
distance from vertex 2 to 4 through vertex (ie. from vertex 2 to 1 and from vertex
1 to 4) is 7.Since 4 < 7, A0 [2,4] is filled with 4.
3. Similarly, A2 is created using A1. The elements in the second column and the
second row areleft as they are.
In this step, k is the second vertex (i.e. vertex 2). The remaining steps are the same
as in step
Calculate the distance from the source vertex to destination vertex through this
87
Course Code/Title:CS3302/Design Analysis of Algorithms
vertex 2
Calculate the distance from the source vertex to destination vertex through this
vertex 4
Floyd-WarshallAlgorithm:
n=no of vertices
A=matrix of dimension n*n
for k = 1 to n
for i = 1 to n
for j= 1to n
Ak[i,j]=min(Ak-1[i,j],Ak-1[i,k]+Ak-1[k,j])
return A
TimeComplexity:
There are three loops. Each loop has constant complexities. So, the time
complexity of the Floyd-Warshall algorithm is O(n3).
NetworkFlow:
Flow Network is a directed graph that is used for modeling material Flow. There are two
different vertices; one is a source which produces material at some steady rate, and another
one is sink which consumes the content at the same constant speed. The flow of the material
at any mark in the system is the rate at which the element moves.
Some real-life problems like the flow of liquids through pipes, the current through wires
88
Course Code/Title:CS3302/Design Analysis of Algorithms
Let G = (V, E) be a flow network. Let s be the source of the network, and let t be the sink.
A flow in G is a real-valued function f: V x V→R such that the following properties hold:
PlayVideo
o Capacity Constraint: For all u,v∈ V,we need f(u,v)≤c(u,v).
o Skew Symmetry: For all u,v∈ V,we need f(u,v)=-f(u,v).
o Flow Conservation: For all u∈V-{s,t},we need
The quantity f(u,v),which can be positive or negative, is known as the netflow from vertex
u to vertex v.In the maximum-flow problem, we are given a flow network G with source s
and sink t, and a flow of maximum value from s to t.
Ford-FulkersonAlgorithm:
Initially, the flow of value is 0. Find some augmenting Path p and increase flow f on each
edge of p by residual Capacity cf (p). When no augmenting path exists, flow f is a maximum
flow.
FORD-FULKERSONMETHOD(G,s,t)
1. Initialize flow f to 0
2. While there exists an augmenting path p
3. Do argument flow f along p
4. Return f
FORD-FULKERSON(G,s,t)
89
Course Code/Title:CS3302/Design Analysis of Algorithms
8. f [u,v]←-f [u,v]
Example: Each Directed Edge is labeled with capacity. Use the Ford-Fulkerson algorithm
to find themaximum flow.
Solution: The left side of each part shows the residual network Gf with a shaded augmenting
path p, and the right side of each part shows the net flow f.
90
Course Code/Title:CS3302/Design Analysis of Algorithms
The bipartite matching is a set of edges in a graph is chosen in such a way, that no two edges in
that set will share an endpoint. The maximum matching is matching the maximum number of
edges.
When the maximum match is found, we cannot add another edge. If one edge is added to the
maximum matched graph, it is no longer a matching. For a bipartite graph, there can be more
than one maximum matching is possible.
Algorithm:
Input: Starting node, visited list to keep track, assign the list to assign node with another node.
Output−Returns true when a matching for vertex u is possible.
Begin
for all vertex v, which are adjacent with u, do if v is not
visited, then
mark v as visited
if v is not assigned, or bipartite Match(assign[v],visited,assign) is true,then assign[v] := u
return true
done
return false
End
maxMatch(graph) Input−The
given graph.
Output−The maximum number of the match.
Begin Initially no vertex is
assignedcount := 0
for all applicant u in M, do
make all node as unvisited
if bipartite Match(u,visited,assign), then,increase count by 1,done, End
91
Course Code/Title:CS3302/Design Analysis of Algorithms
The divide-and-conquer technique involves taking a large-scale problem and dividing it into similar sub-
problems of a smaller scale and recursively solving each of these sub-problems. Generally, a problem is
divided into sub-problems repeatedly until the resulting sub-problems are very easy to solve.
Let T(n) be the time complexity of a divide-and-conquer algorithm to solve this problem. Then T(n)
satisfies an equation of the form: T(n) = a T(n/b) + f (n). 1 is the number of recursively calls and n/b with
b > 1 is the size of a sub-problem.
Finding Maximum and Minimum Element using Divide and Conquer Method:
Max-Min Problem
The Max-Min Problem in algorithm analysis is finding the maximum and minimum value in an array.
Solution
To find the maximum and minimum numbers in a given array numbers[] of size n, the following algorithm
can be used. First we are representing the naive method and then we will present divide and conquer
approach.
Naive Method
Naive method is a basic method to solve any problem. In this method, the maximum and minimum number
can be found separately. To find the maximum and minimum numbers, the following straightforward
algorithm can be used.
Algorithm: Max-Min-Element (numbers[])
max := numbers[1]
min := numbers[1]
for i = 2 to n do
if numbers[i] > max then
max := numbers[i]
if numbers[i] < min then
min := numbers[i]
return (max, min)
Example
Program:
#include <stdio.h>
struct Pair {
int max;
int min;
};
// Function to find maximum and minimum using the naive algorithm
struct Pair maxMinNaive(int arr[], int n) {
struct Pair result;
result.max = arr[0];
result.min = arr[0];
// Loop through the array to find the maximum and minimum values
for (int i = 1; i < n; i++) {
92
Course Code/Title:CS3302/Design Analysis of Algorithms
93
Course Code/Title:CS3302/Design Analysis of Algorithms
int max;
int min;
};
struct Pair maxMinDivideConquer(int arr[], int low, int high) {
struct Pair result;
struct Pair left;
struct Pair right;
int mid;
// If only one element in the array
if (low == high) {
result.max = arr[low];
result.min = arr[low];
return result;
}
// If there are two elements in the array
if (high == low + 1) {
if (arr[low] < arr[high]) {
result.min = arr[low];
result.max = arr[high];
} else {
result.min = arr[high];
result.max = arr[low];
}
return result;
}
// If there are more than two elements in the array
mid = (low + high) / 2;
left = maxMinDivideConquer(arr, low, mid);
right = maxMinDivideConquer(arr, mid + 1, high);
// Compare and get the maximum of both parts
result.max = (left.max > right.max) ? left.max : right.max;
// Compare and get the minimum of both parts
result.min = (left.min < right.min) ? left.min : right.min;
return result;
}
int main() {
int arr[] = {6, 4, 26, 14, 33, 64, 46};
int n = sizeof(arr) / sizeof(arr[0]);
struct Pair result = maxMinDivideConquer(arr, 0, n - 1);
printf("Maximum element is: %d\n", result.max);
printf("Minimum element is: %d\n", result.min);
return 0;
}
94
Course Code/Title:CS3302/Design Analysis of Algorithms
Output
Maximum element is: 64
Minimum element is: 4
Analysis
Let T(n) be the number of comparisons made by [Math Processing Error]Max−Min(x,y), where the
number of elements [Math Processing Error]n=y−x+1.
If T(n) represents the numbers, then the recurrence relation can be represented as
[Math Processing Error]T(n)={T(⌊n2⌋)+T(⌈n2⌉)+2forn>21forn=20forn=1
Let us assume that n is in the form of power of 2. Hence, n = 2k where k is height of the recursion tree.
So,
[Math Processing Error]T(n)=2.T(n2)+2=2.(2.T(n4)+2)+2.....=3n2−2
Compared to Naïve method, in divide and conquer approach, the number of comparisons is less. However,
using the asymptotic notation both of the approaches are represented by O(n).
Merge Sort:
Merge sort is yet another sorting algorithm that falls under the category of Divide and Conquer technique.
It is one of the best sorting techniques that successfully build a recursive algorithm.
Divide and Conquer Strategy
In this technique, we segment a problem into two halves and solve them individually. After finding the
solution of each half, we merge them back to represent the solution of the main problem.
Suppose we have an array A, such that our main concern will be to sort the subsection, which starts at
index p and ends at index r, represented by A[p..r].
Divide
If assumed q to be the central point somewhere in between p and r, then we will fragment the
subarray A[p..r] into two arrays A[p..q] and A[q+1, r].
Conquer
After splitting the arrays into two halves, the next step is to conquer. In this step, we individually sort both
of the subarrays A[p..q] and A[q+1, r]. In case if we did not reach the base situation, then we again follow
the same procedure, i.e., we further segment these subarrays followed by sorting them separately.
Combine
As when the base step is acquired by the conquer step, we successfully get our sorted
subarrays A[p..q] and A[q+1, r], after which we merge them back to form a new sorted array [p..r].
Merge Sort algorithm
The MergeSort function keeps on splitting an array into two halves until a condition is met where we try to
perform MergeSort on a subarray of size 1, i.e., p == r.
And then, it combines the individually sorted subarrays into larger arrays until the whole array is merged.
ALGORITHM-MERGE SORT
1. If p<r
2. Then q → ( p+ r)/2
3. MERGE-SORT (A, p, q)
4. MERGE-SORT ( A, q+1,r)
5. MERGE ( A, p, q, r)
Here we called MergeSort(A, 0, length(A)-1) to sort the complete array.
95
Course Code/Title:CS3302/Design Analysis of Algorithms
As you can see in the image given below, the merge sort algorithm recursively divides the array into halves
until the base condition is met, where we are left with only 1 element in the array. And then, the merge
function picks up the sorted sub-arrays and merge them back to sort the entire array.
The following figure illustrates the dividing (splitting) procedure.
96
Course Code/Title:CS3302/Design Analysis of Algorithms
97
Course Code/Title:CS3302/Design Analysis of Algorithms
as they were in the original array. After now, we will further divide these two arrays into other halves.
Step3: Again, we will divide these arrays until we achieve an atomic value, i.e., a value that cannot be
further divided.
Step4: Next, we will merge them back in the same way as they were broken down.
Step5: For each list, we will first compare the element and then combine them to form a new sorted list.
Step6: In the next iteration, we will compare the lists of two data values and merge them back into a list of
found data values, all placed in a sorted manner.
But we ignore '-1' because the element will take some time to be copied in merge lists.
98
Course Code/Title:CS3302/Design Analysis of Algorithms
So T (n) = 2T + n...equation 1
Note: Stopping Condition T (1) =0 because at last, there will be only 1 element left that need to be copied,
and there will be no comparison.
99
Course Code/Title:CS3302/Design Analysis of Algorithms
logn= i log2
=i
log2 n=i
From 6 equation
Best Case Complexity: The merge sort algorithm has a best-case time complexity of O(n*log n) for the
already sorted array.
Average Case Complexity: The average-case time complexity for the merge sort algorithm is O(n*log n),
which happens when 2 or more elements are jumbled, i.e., neither in the ascending order nor in the
descending order.
Worst Case Complexity: The worst-case time complexity is also O(n*log n), which occurs when we sort
the descending order of an array into the ascending order.
Space Complexity: The space complexity of merge sort is O(n).
Quick Sort:
It is an algorithm of Divide & Conquer type.
Divide: Rearrange the elements and split arrays into two sub-arrays and an element in between search that
each element in left sub array is less than or equal to the average element and each element in the right sub-
array is larger than the middle element.
Conquer: Recursively, sort two sub arrays.
Combine: Combine the already sorted array.
Algorithm:
QUICKSORT (array A, int m, int n)
1 if (n > m)
2 then
3 i ← a random index from [m,n]
4 swap A [i] with A[m]
5 o ← PARTITION (A, m, n)
6 QUICKSORT (A, m, o - 1)
7 QUICKSORT (A, o + 1, n)
Partition Algorithm:
Partition algorithm rearranges the sub arrays in a place.
PARTITION (array A, int m, int n)
1 x ← A[m]
2o←m
3 for p ← m + 1 to n
100
Course Code/Title:CS3302/Design Analysis of Algorithms
4 do if (A[p] < x)
5 then o ← o + 1
6 swap A[o] with A[p]
7 swap A[m] with A[o]
8 return o
Figure: shows the execution trace partition algorithm
101
Course Code/Title:CS3302/Design Analysis of Algorithms
22 33 11 40 44 90 77 60 99 55 88
Now, the element on the right side and left side are greater than and smaller than 44 respectively.
Now we get two sorted lists:
And these sublists are sorted under the same process as above done.
These two sorted sublists side by side.
Merging Sublists:
SORTED LISTS
Worst Case Analysis: It is the case when items are already in sorted form and we try to sort them again.
This will takes lots of time and space.
Equation:
1. T (n) =T(1)+T(n-1)+n
T (1) is time taken by pivot element.
T (n-1) is time taken by remaining element except for pivot element.
N: the number of comparisons required to identify the exact position of itself (every element)
If we compare first element pivot with other, then there will be 5 comparisons.
It means there will be n comparisons if there are n items.
102
Course Code/Title:CS3302/Design Analysis of Algorithms
Note: for making T (n-4) as T (1) we will put (n-1) in place of '4' and if
We put (n-1) in place of 4 then we have to put (n-2) in place of 3 and (n-3)
In place of 2 and so on.
T(n)=(n-1) T(1) + T(n-(n-1))+(n-(n-2))+(n-(n-3))+(n-(n-4))+n
T (n) = (n-1) T (1) + T (1) + 2 + 3 + 4+............n
T (n) = (n-1) T (1) +T (1) +2+3+4+...........+n+1-1
103
Course Code/Title:CS3302/Design Analysis of Algorithms
Pivot element will do n comparison and we are doing average case so,
104
Course Code/Title:CS3302/Design Analysis of Algorithms
= n+1 + (T(0)+T(1)+T(2)+...T(n-1)+T(n-2)+T(n-3)+...T(0))
= n+1 + x2 (T(0)+T(1)+T(2)+...T(n-2)+T(n-1))
Put n=n-1 in eq 3
Put 4 eq in 3 eq
Put n=n-2 in eq 3
Put 6 eq in 5 eq
105
Course Code/Title:CS3302/Design Analysis of Algorithms
Put n=n-3 in eq 3
Put 8 eq in 7 eq
From 10 eq
106
Course Code/Title:CS3302/Design Analysis of Algorithms
107
Course Code/Title:CS3302/Design Analysis of Algorithms
Dynamic Programming
Dynamic programming is a technique that breaks the problems into sub-problems, and saves the result for
future purposes so that we do not need to compute the result again. The subproblems are optimized to
optimize the overall solution is known as optimal substructure property. The main use of dynamic
programming is to solve optimization problems. Here, optimization problems mean that when we are trying
to find out the minimum or the maximum solution of a problem. The dynamic programming guarantees to
find the optimal solution of a problem if the solution exists.
The definition of dynamic programming says that it is a technique for solving a complex problem by first
breaking into a collection of simpler subproblems, solving each subproblem just once, and then storing
their solutions to avoid repetitive computations.
Let's understand this approach through an example.
Consider an example of the Fibonacci series. The following series is the Fibonacci series:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ,…
The numbers in the above series are not randomly calculated. Mathematically, we could write each of the
terms using the below formula:
F(n) = F(n-1) + F(n-2),
With the base values F(0) = 0, and F(1) = 1. To calculate the other numbers, we follow the above
relationship. For example, F(2) is the sum f(0) and f(1), which is equal to 1.
How can we calculate F(20)?
The F(20) term will be calculated using the nth formula of the Fibonacci series. The below figure shows
that how F(20) is calculated.
108
Course Code/Title:CS3302/Design Analysis of Algorithms
As we can observe in the above figure that F(20) is calculated as the sum of F(19) and F(18). In the dynamic
programming approach, we try to divide the problem into the similar subproblems. We are following this
approach in the above case where F(20) into the similar subproblems, i.e., F(19) and F(18). If we recap the
definition of dynamic programming that it says the similar subproblem should not be computed more than
once. Still, in the above case, the subproblem is calculated twice. In the above example, F(18) is calculated
two times; similarly, F(17) is also calculated twice. However, this technique is quite useful as it solves the
similar subproblems, but we need to be cautious while storing the results because we are not particular
about storing the result that we have computed once, then it can lead to a wastage of resources.
In the above example, if we calculate the F(18) in the right subtree, then it leads to the tremendous usage
of resources and decreases the overall performance.
The solution to the above problem is to save the computed results in an array. First, we calculate F(16) and
F(17) and save their values in an array. The F(18) is calculated by summing the values of F(17) and F(16),
which are already saved in an array. The computed value of F(18) is saved in an array. The value of F(19)
is calculated using the sum of F(18), and F(17), and their values are already saved in an array. The computed
value of F(19) is stored in an array. The value of F(20) can be calculated by adding the values of F(19) and
F(18), and the values of both F(19) and F(18) are stored in an array. The final computed value of F(20) is
stored in an array.
How does the dynamic programming approach work?
The following are the steps that the dynamic programming follows:
o It breaks down the complex problem into simpler subproblems.
109
Course Code/Title:CS3302/Design Analysis of Algorithms
o Bottom-up approach
Top-down approach
The top-down approach follows the memorization technique, while bottom-up approach follows the
tabulation method. Here memorization is equal to the sum of recursion and caching. Recursion means
calling the function itself, while caching means storing the intermediate results.
Advantages
o It is very easy to understand and implement.
110
Course Code/Title:CS3302/Design Analysis of Algorithms
In the above code, we have used the recursive approach to find out the Fibonacci series. When the value of
'n' increases, the function calls will also increase, and computations will also increase. In this case, the time
complexity increases exponentially, and it becomes 2n.
One solution to this problem is to use the dynamic programming approach. Rather than generating the
recursive tree again and again, we can reuse the previously calculated value. If we use the dynamic
programming approach, then the time complexity would be O(n).
When we apply the dynamic programming approach in the implementation of the Fibonacci series, then
the code would look like:
static int count = 0;
int fib(int n)
{
if(memo[n]!= NULL)
return memo[n];
count++;
if(n<0)
error;
if(n==0)
return 0;
if(n==1)
return 1;
sum = fib(n-1) + fib(n-2);
memo[n] = sum;
}
In the above code, we have used the memorization technique in which we store the results in an array to
reuse the values. This is also known as a top-down approach in which we move from the top and break the
problem into sub-problems.
Bottom-Up approach
The bottom-up approach is also one of the techniques which can be used to implement the dynamic
programming. It uses the tabulation technique to implement the dynamic programming approach. It solves
the same kind of problems but it removes the recursion. If we remove the recursion, there is no stack
overflow issue and no overhead of the recursive functions. In this tabulation technique, we solve the
problems and store the results in a matrix.
There are two ways of applying dynamic programming:
111
Course Code/Title:CS3302/Design Analysis of Algorithms
o Top-Down
o Bottom-Up
The bottom-up is the approach used to avoid the recursion, thus saving the memory space. The bottom-up
is an algorithm that starts from the beginning, whereas the recursive algorithm starts from the end and works
backward. In the bottom-up approach, we start from the base case to find the answer for the end. As we
know, the base cases in the Fibonacci series are 0 and 1. Since the bottom approach starts from the base
cases, so we will start from 0 and 1.
Key points
o We solve all the smaller sub-problems that will be needed to solve the larger sub-problems then
move to the larger problems using smaller sub-problems.
o We use for loop to iterate over the sub-problems.
o The bottom-up approach is also known as the tabulation or table filling method.
Let's understand through an example.
Suppose we have an array that has 0 and 1 values at a[0] and a[1] positions, respectively shown as below:
Since the bottom-up approach starts from the lower values, so the values at a[0] and a[1] are added to find
the value of a[2] shown as below:
The value of a[3] will be calculated by adding a[1] and a[2], and it becomes 2 shown as below:
The value of a[4] will be calculated by adding a[2] and a[3], and it becomes 3 shown as below:
The value of a[5] will be calculated by adding the values of a[4] and a[3], and it becomes 5 shown as below:
The code for implementing the Fibonacci series using the bottom-up approach is given below:
int fib(int n)
{
int A[];
112
Course Code/Title:CS3302/Design Analysis of Algorithms
A[0] = 0, A[1] = 1;
for( i=2; i<=n; i++)
{
A[i] = A[i-1] + A[i-2]
}
return A[n];
}
In the above code, base cases are 0 and 1 and then we have used for loop to find other values of Fibonacci
series.
Let's understand through the diagrammatic representation.
Initially, the first two values, i.e., 0 and 1 can be represented as:
When i=2 then the values 0 and 1 are added shown as below:
When i=3 then the values 1and 1 are added shown as below:
When i=4 then the values 2 and 1 are added shown as below:
113
Course Code/Title:CS3302/Design Analysis of Algorithms
When i=5, then the values 3 and 2 are added shown as below:
114
Course Code/Title:CS3302/Design Analysis of Algorithms
Let us proceed with working away from the diagonal. We compute the optimal solution for the product of
2 matrices.
In Dynamic Programming, initialization of every method done by '0'.So we initialize it by '0'.It will sort out
diagonally.
We have to sort out all the combination but the minimum output combination is taken into consideration.
Calculation of Product of 2 matrices:
1. m (1,2) = m1 x m2
= 4 x 10 x 10 x 3
= 4 x 10 x 3 = 120
2. m (2, 3) = m2 x m3
= 10 x 3 x 3 x 12
= 10 x 3 x 12 = 360
3. m (3, 4) = m3 x m4
= 3 x 12 x 12 x 20
= 3 x 12 x 20 = 720
4. m (4,5) = m4 x m5
= 12 x 20 x 20 x 7
= 12 x 20 x 7 = 1680
115
Course Code/Title:CS3302/Design Analysis of Algorithms
o We initialize the diagonal element with equal i,j value with '0'.
o After that second diagonal is sorted out and we get all the values corresponded to it
Now the third diagonal will be solved out in the same way.
Now product of 3 matrices:
M [1, 3] = M1 M2 M3
1. There are two cases by which we can solve this multiplication: ( M1 x M2) + M3, M1+ (M2x M3)
2. After solving both cases we choose the case in which minimum output is there.
M [1, 3] =264
As Comparing both output 264 is minimum in both cases so we insert 264 in table and ( M1 x M2) + M3 this
combination is chosen for the output making.
M [2, 4] = M2 M3 M4
1. There are two cases by which we can solve this multiplication: (M2x M3)+M4, M2+(M3 x M4)
2. After solving both cases we choose the case in which minimum output is there.
M [2, 4] = 1320
As Comparing both output 1320 is minimum in both cases so we insert 1320 in table and M2+(M3 x M4)
this combination is chosen for the output making.
M [3, 5] = M3 M4 M5
1. There are two cases by which we can solve this multiplication: ( M3 x M4) + M5, M3+ ( M4xM5)
2. After solving both cases we choose the case in which minimum output is there.
M [3, 5] = 1140
As Comparing both output 1140 is minimum in both cases so we insert 1140 in table and ( M3 x M4) +
M5this combination is chosen for the output making.
116
Course Code/Title:CS3302/Design Analysis of Algorithms
M [1, 4] =1080
As comparing the output of different cases then '1080' is minimum output, so we insert 1080 in the table
and (M1 xM2) x (M3 x M4) combination is taken out in output making,
M [2, 5] = M2 M3 M4 M5
There are three cases by which we can solve this multiplication:
1. (M2 x M3 x M4)x M5
2. M2 x( M3 x M4 x M5)
3. (M2 x M3)x ( M4 x M5)
After solving these cases we choose the case in which minimum output is there
M [2, 5] = 1350
As comparing the output of different cases then '1350' is minimum output, so we insert 1350 in the table
and M2 x( M3 x M4 xM5)combination is taken out in output making.
117
Course Code/Title:CS3302/Design Analysis of Algorithms
2. M1 x( M2 xM3 x M4 xM5)
3. (M1 x M2 xM3)x M4 xM5
4. M1 x M2x(M3 x M4 xM5)
After solving these cases we choose the case in which minimum output is there
M [1, 5] = 1344
As comparing the output of different cases then '1344' is minimum output, so we insert 1344 in the table
and M1 x M2 x(M3 x M4 x M5)combination is taken out in output making.
Final Output is:
Step 3: Computing Optimal Costs: let us assume that matrix Ai has dimension pi-1x pi for i=1, 2, 3....n.
The input is a sequence (p0,p1,......pn) where length [p] = n+1. The procedure uses an auxiliary table m
[1....n, 1.....n] for storing m [i, j] costs an auxiliary table s [1.....n, 1.....n] that record which index of k
achieved the optimal costs in computing m [i, j].
The algorithm first computes m [i, j] ← 0 for i=1, 2, 3.....n, the minimum costs for the chain of length 1.
Multistage Graph
A multistage graph is a directed and weighted graph, in which all vertices are divided into stages, such that
all the edges are only directed from the vertex of the current stage to the vertex of the next stage (i.e there
is no edge between the vertex of the same stage and to the previous stage vertex). Both the first and last
stage contains only one vertex called source and destination/sink respectively.
Mathematically, a multistage graph can be defined as:
Multistage graph G = (V, E, W) is a weighted directed graph in which vertices are partitioned into k ≥ 2
disjoint subsets V = {V1, V2, …, Vk} such that if edge (u, v) is present in E then u ∈ Vi and v ∈ Vi+1, 1 ≤
i ≤ k. The sets V1 and Vk are such that |V1 | = |Vk|=1
118
Course Code/Title:CS3302/Design Analysis of Algorithms
119
Course Code/Title:CS3302/Design Analysis of Algorithms
3. Finally, the cost from 1st vertex cost(1,k) gives the minimum cost of the shortest path from source
to destination.
4. For finding the path, start from vertex-1 then the distance array D(1) will give the minimum cost
neighbour vertex which in turn gives the next nearest vertex and proceed in this way till we reach
the destination. For a ‘k’ stage graph, there will be ‘k’ vertex in the path.
5. For forward approach,
Cost (i,j) = min {C (j,l) + Cost (i+1,l) } l∈Vi + 1 & (j,l)∈E
Algorithm:
MULTI_STAGE(G, k, n, p)
// Description: Solve multi-stage problem using dynamic programming
// Input:
k: Number of stages in graph G = (V, E)
c[i, j]:Cost of edge (i, j)
// Output: p[1:k]:Minimum cost path
cost[n] ← 0
for j ← n — 1 to 1 do
//Let r be a vertex such that (j, r) E and c[j, r] + cost[r] is minimum
cost[j] ← c[j, r] + cost[r]
π[j] ← r
end
//Find minimum cost path
p[1] ← 1
p[k] ← n
for j ← 2 to k — 1 do
p[j] ← π[p[j — 1]]
end
Code:
// CPP program to find shortest distance
// in a multistage graph.
#include<bits/stdc++.h>
using namespace std;
#define N 12
#define INF INT_MAX
// Returns shortest distance from 0 to
// N-1.
int shortestDist(int graph[N][N]) {
// dist[i] is going to store shortest
// distance from node i to node N-1.
int dist[N];
dist[N-1] = 0;
120
Course Code/Title:CS3302/Design Analysis of Algorithms
121
Course Code/Title:CS3302/Design Analysis of Algorithms
Solution:
In the above graph, cost of an edge is represented as c(i, j). We need to find the minimum cost path from
vertex 1 to vertex 12. Using the below formula we can find the shortest cost path from source to destination:
cost(i,j)=min{c(j,l)+cost(i+1,l)}
Step 1:
Stage 5
cost(5,12)=c(12,12)=0
We use forward approach here therefore (cost(5,12) = 0 ). Here, 5 represents the stage number and 12
represents a node in that stage. Since there are no outgoing edges from vertex 12, the cost is 0 and D[12]=12
Step 2:
Stage 4
cost(4,9)= c(9,12) = 4 D[9]=12
cost(4,10) = c(10,12) = 2 D[10]=12
cost(4,11) = c(11,12) = 5 D[11]=12
Step 3:
Stage 3
cost(3,6)=min{c(6,9)+cost(4,9), c(6,10)+cost(4,10)}
= min{6+4,5+2} =min{10,7}=7 D[6]=10
cost(3,7)=min{c(7,9)+cost(4,9), c(7,10)+cost(4,10)}
= min{4+4,3+2} =min{8,5}=5 D[7]=10
122
Course Code/Title:CS3302/Design Analysis of Algorithms
cost(3,8)=min{c(8,10)+cost(4,10), c(8,11)+cost(4,10)}
= min{5+2,6+5} =min{7,11}=7 D[7]=10
Step 4:
Stage 2
cost(2,2) = min{c(2,6)+cost(3,6), c(2,7)+cost(3,7), c(2,8)+cost(3,8)}
= min{4+7,2+5,1+7}=min{11,7,8}=7 D[2]=7
cost(2,3) = min{c(3,6)+cost(3,6), c(3,7)+cost(3,7)}
= min{2+7,7+5}=min{9,12}=9 D[3]=6
cost(2,4) = min{c(4,8)+cost(3,8)}
= min{11+7}=min{18}=18 D[4]=8
cost(2,5) = min{c(5,7)+cost(3,7), c(5,8)+cost(3,8)}
= min{11+5,8+7}=min{16,15}=15 D[3]=8
Step 5:
Stage 1
cost(1,1) = min(c(1,2)+cost(2,2), c(1,3)+cost(2,3), c(1,4)+cost(2,4), c(1,5)+cost(2,5)}
= min{9+7, 7+9, 3+18, 2+15}=min{16,16,21,17}=16
D[1] = 2 (we can take 3 also )
The path through which we have to find the shortest distance
Start from vertex — 2
D ( 1) = 2
D ( 2) = 7
D ( 7) = 10
D (10) = 12
So, the minimum –cost path is,
123
Course Code/Title:CS3302/Design Analysis of Algorithms
4. To find out the path star from vertex ‘k’, then the distance array D (k) will give the minimum cost
neighbour vertex which in turn gives the next nearest neighbour vertex and proceed till we reach
the destination.
Application of multistage graph :
1. It is used to find the minimum cost shortest path.
2. If a problem can be represented as a multistage graph then it can be solved by dynamic
programming.
In the above tree, all the nodes on the left subtree are smaller than the value of the root node, and all the
nodes on the right subtree are larger than the value of the root node. The maximum time required to search
a node is equal to the minimum height of the tree, equal to logn.
Now we will see how many binary search trees can be made from the given number of keys.
For example: 10, 20, 30 are the keys, and the following are the binary search trees that can be made out
from these keys.
The Formula for calculating the number of trees:
124
Course Code/Title:CS3302/Design Analysis of Algorithms
When we use the above formula, then it is found that total 5 number of trees can be created.
The cost required for searching an element depends on the comparisons to be made to search an element.
Now, we will calculate the average cost of time of the above binary search trees.
In the above tree, total number of 3 comparisons can be made. The average number of comparisons can be
made as:
In the above tree, the average number of comparisons that can be made as:
In the above tree, the average number of comparisons that can be made as:
125
Course Code/Title:CS3302/Design Analysis of Algorithms
In the above tree, the total number of comparisons can be made as 3. Therefore, the average number of
comparisons that can be made as:
In the above tree, the total number of comparisons can be made as 3. Therefore, the average number of
comparisons that can be made as:
In the third case, the number of comparisons is less because the height of the tree is less, so it's a balanced
binary search tree.
Till now, we read about the height-balanced binary search tree. To find the optimal binary search tree, we
will determine the frequency of searching a key.
Let's assume that frequencies associated with the keys 10, 20, 30 are 3, 2, 5.
The above trees have different frequencies. The tree with the lowest frequency would be considered the
optimal binary search tree. The tree with the frequency 17 is the lowest, so it would be considered as the
optimal binary search tree.
Dynamic Approach
Consider the below table, which contains the keys and frequencies.
126
Course Code/Title:CS3302/Design Analysis of Algorithms
127
Course Code/Title:CS3302/Design Analysis of Algorithms
o When i=0 and j=2, then keys 10 and 20. There are two possible trees that can be made out from
these two keys shown below:
o When i=1 and j=3, then keys 20 and 30. There are two possible trees that can be made out from
these two keys shown below:
In the first binary tree, cost would be: 1*2 + 2*6 = 14
In the second binary tree, cost would be: 1*6 + 2*2 = 10
The minimum cost is 10; therefore, c[1,3] = 10
o When i=2 and j=4, we will consider the keys at 3 and 4, i.e., 30 and 40. There are two possible trees
that can be made out from these two keys shown as below:
In the first binary tree, cost would be: 1*6 + 2*3 = 12
In the second binary tree, cost would be: 1*3 + 2*6 = 15
The minimum cost is 12, therefore, c[2,4] = 12
128
Course Code/Title:CS3302/Design Analysis of Algorithms
The following are the trees that can be made if 10 is considered as a root node.
In the above tree, 10 is the root node, 20 is the right child of node 10, and 30 is the right child of node 20.
Cost would be: 1*4 + 2*2 + 3*6 = 26
In the above tree, 10 is the root node, 30 is the right child of node 10, and 20 is the left child of node 20.
Cost would be: 1*4 + 2*6 + 3*2 = 22
The following tree can be created if 20 is considered as the root node.
129
Course Code/Title:CS3302/Design Analysis of Algorithms
In the above tree, 20 is the root node, 30 is the right child of node 20, and 10 is the left child of node 20.
Cost would be: 1*2 + 4*2 + 6*2 = 22
The following are the trees that can be created if 30 is considered as the root node.
In the above tree, 30 is the root node, 20 is the left child of node 30, and 10 is the left child of node 20.
Cost would be: 1*6 + 2*2 + 3*4 = 22
In the above tree, 30 is the root node, 10 is the left child of node 30 and 20 is the right child of node 10.
Cost would be: 1*6 + 2*4 + 3*2 = 20
Therefore, the minimum cost is 20 which is the 3rd root. So, c[0,3] is equal to 20.
o When i=1 and j=4 then we will consider the keys 20, 30, 40
130
Course Code/Title:CS3302/Design Analysis of Algorithms
131
Course Code/Title:CS3302/Design Analysis of Algorithms
132
Course Code/Title:CS3302/Design Analysis of Algorithms
Si = (1,2,3,4,7,8,9,9,11,12)
fi = (3,5,4,7,10,9,11,13,12,14)
Compute a schedule where the greatest number of activities takes place.
Solution: The solution to the above Activity scheduling problem using a greedy strategy is illustrated
below:
Arranging the activities in increasing order of end time
Now, schedule A1
Next schedule A3 as A1 and A3 are non-interfering.
Next skip A2 as it is interfering.
Next, schedule A4 as A1 A3 and A4 are non-interfering, then next, schedule A6 as A1 A3 A4 and A6 are non-
interfering.
Skip A5 as it is interfering.
Next, schedule A7 as A1 A3 A4 A6 and A7 are non-interfering.
Next, schedule A9 as A1 A3 A4 A6 A7 and A9 are non-interfering.
Skip A8 as it is interfering.
Next, schedule A10 as A1 A3 A4 A6 A7 A9 and A10 are non-interfering.
Thus the final Activity schedule is:
133
Course Code/Title:CS3302/Design Analysis of Algorithms
134
Course Code/Title:CS3302/Design Analysis of Algorithms
Step 1
Step 2
Step 3
Step 4
135
Course Code/Title:CS3302/Design Analysis of Algorithms
136
Course Code/Title:CS3302/Design Analysis of Algorithms
24 = 16; So. There are 16 possible combinations that can be made by using the above problem. Once all the
combinations are made, we have to select the combination that provides the maximum profit.
Another approach to solve the problem is dynamic programming approach. In dynamic programming
approach, the complicated problem is divided into sub-problems, then we find the solution of a sub-problem
and the solution of the sub-problem will be used to find the solution of a complex problem.
How this problem can be solved by using the Dynamic programming approach?
First,
we create a matrix shown as below:
0 1 2 3 4 5 6 7 8
4
In the above matrix, columns represent the weight, i.e., 8. The rows represent the profits and weights of
items. Here we have not taken the weight 8 directly, problem is divided into sub-problems, i.e., 0, 1, 2, 3,
4, 5, 6, 7, 8. The solution of the sub-problems would be saved in the cells and answer to the problem would
be stored in the final cell. First, we write the weights in the ascending order and profits according to their
weights shown as below:
wi = {3, 4, 5, 6}
pi = {2, 3, 4, 1}
The first row and the first column would be 0 as there is no item for w=0
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0
2 0
3 0
4 0
When i=1, W=1
w1 = 3; Since we have only one item in the set having weight 3, but the capacity of the knapsack is 1. We
cannot fill the item of 3kg in the knapsack of capacity 1 kg so add 0 at M[1][1] shown as below:
137
Course Code/Title:CS3302/Design Analysis of Algorithms
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0
2 0
3 0
4 0
When i = 1, W = 2
w1 = 3; Since we have only one item in the set having weight 3, but the capacity of the knapsack is 2. We
cannot fill the item of 3kg in the knapsack of capacity 2 kg so add 0 at M[1][2] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0
2 0
3 0
4 0
When i=1, W=3
w1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is also
3; therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][3] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2
2 0
3 0
4 0
When i=1, W = 4
138
Course Code/Title:CS3302/Design Analysis of Algorithms
W1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is 4;
therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][4] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2
2 0
3 0
4 0
When i=1, W = 5
W1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is 5;
therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][5] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2
2 0
3 0
4 0
When i =1, W=6
W1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is 6;
therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][6] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2
2 0
139
Course Code/Title:CS3302/Design Analysis of Algorithms
3 0
4 0
When i=1, W = 7
W1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is 7;
therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][7] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2
2 0
3 0
4 0
When i =1, W =8
W1 = 3; Since we have only one item in the set having weight equal to 3, and weight of the knapsack is 8;
therefore, we can fill the knapsack with an item of weight equal to 3. We put profit corresponding to the
weight 3, i.e., 2 at M[1][8] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0
3 0
4 0
Now the value of 'i' gets incremented, and becomes 2.
When i =2, W = 1
The weight corresponding to the value 2 is 4, i.e., w 2 = 4. Since we have only one item in the set having
weight equal to 4, and the weight of the knapsack is 1. We cannot put the item of weight 4 in a knapsack,
so we add 0 at M[2][1] shown as below:
0 1 2 3 4 5 6 7 8
140
Course Code/Title:CS3302/Design Analysis of Algorithms
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0
3 0
4 0
When i =2, W = 2
The weight corresponding to the value 2 is 4, i.e., w 2 = 4. Since we have only one item in the set having
weight equal to 4, and the weight of the knapsack is 2. We cannot put the item of weight 4 in a knapsack,
so we add 0 at M[2][2] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0
3 0
4 0
When i =2, W = 3
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
3 and 4, and the weight of the knapsack is 3. We can put the item of weight 3 in a knapsack, so we add 2 at
M[2][3] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2
3 0
4 0
When i =2, W = 4
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
141
Course Code/Title:CS3302/Design Analysis of Algorithms
3 and 4, and the weight of the knapsack is 4. We can put item of weight 4 in a knapsack as the profit
corresponding to weight 4 is more than the item having weight 3, so we add 3 at M[2][4] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3
3 0
4 0
When i = 2, W = 5
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
3 and 4, and the weight of the knapsack is 5. We can put item of weight 4 in a knapsack and the profit
corresponding to weight is 3, so we add 3 at M[2][5] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3
3 0
4 0
When i = 2, W = 6
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
3 and 4, and the weight of the knapsack is 6. We can put item of weight 4 in a knapsack and the profit
corresponding to weight is 3, so we add 3 at M[2][6] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3
3 0
142
Course Code/Title:CS3302/Design Analysis of Algorithms
4 0
When i = 2, W = 7
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
3 and 4, and the weight of the knapsack is 7. We can put item of weight 4 and 3 in a knapsack and the
profits corresponding to weights are 2 and 3; therefore, the total profit is 5, so we add 5 at M[2][7] shown
as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 0 3 3 3 5
3 0
4 0
When i = 2, W = 8
The weight corresponding to the value 2 is 4, i.e., w2 = 4. Since we have two items in the set having weights
3 and 4, and the weight of the knapsack is 7. We can put item of weight 4 and 3 in a knapsack and the
profits corresponding to weights are 2 and 3; therefore, the total profit is 5, so we add 5 at M[2][7] shown
as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0
4 0
Now the value of 'i' gets incremented, and becomes 3.
When i = 3, W = 1
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set having
weights 3, 4, and 5, and the weight of the knapsack is 1. We cannot put neither of the items in a knapsack,
so we add 0 at M[3][1] shown as below:
0 1 2 3 4 5 6 7 8
143
Course Code/Title:CS3302/Design Analysis of Algorithms
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0
4 0
When i = 3, W = 2
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set having weight
3, 4, and 5, and the weight of the knapsack is 1. We cannot put neither of the items in a knapsack, so we
add 0 at M[3][2] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0
4 0
When i = 3, W = 3
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
4, and 5 respectively and weight of the knapsack is 3. The item with a weight 3 can be put in the knapsack
and the profit corresponding to the item is 2, so we add 2 at M[3][3] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2
4 0
When i = 3, W = 4
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
144
Course Code/Title:CS3302/Design Analysis of Algorithms
4, and 5 respectively, and weight of the knapsack is 4. We can keep the item of either weight 3 or 4; the
profit (3) corresponding to the weight 4 is more than the profit corresponding to the weight 3 so we add 3
at M[3][4] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3
4 0
When i = 3, W = 5
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
4, and 5 respectively, and weight of the knapsack is 5. We can keep the item of either weight 3, 4 or 5; the
profit (3) corresponding to the weight 4 is more than the profits corresponding to the weight 3 and 5 so we
add 3 at M[3][5] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3
4 0
When i =3, W = 6
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
4, and 5 respectively, and weight of the knapsack is 6. We can keep the item of either weight 3, 4 or 5; the
profit (3) corresponding to the weight 4 is more than the profits corresponding to the weight 3 and 5 so we
add 3 at M[3][6] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
145
Course Code/Title:CS3302/Design Analysis of Algorithms
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3
4 0
When i =3, W = 7
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
4, and 5 respectively, and weight of the knapsack is 7. In this case, we can keep both the items of weight 3
and 4, the sum of the profit would be equal to (2 + 3), i.e., 5, so we add 5 at M[3][7] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5
4 0
When i = 3, W = 8
The weight corresponding to the value 3 is 5, i.e., w3 = 5. Since we have three items in the set of weight 3,
4, and 5 respectively, and the weight of the knapsack is 8. In this case, we can keep both the items of weight
3 and 4, the sum of the profit would be equal to (2 + 3), i.e., 5, so we add 5 at M[3][8] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0
Now the value of 'i' gets incremented and becomes 4.
When i = 4, W = 1
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 1. The weight of all the items is more than the
weight of the knapsack, so we cannot add any item in the knapsack; Therefore, we add 0 at M[4][1] shown
as below:
146
Course Code/Title:CS3302/Design Analysis of Algorithms
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0 0
When i = 4, W = 2
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 2. The weight of all the items is more than the
weight of the knapsack, so we cannot add any item in the knapsack; Therefore, we add 0 at M[4][2] shown
as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0 0 0
When i = 4, W = 3
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 3. The item with a weight 3 can be put in the
knapsack and the profit corresponding to the weight 4 is 2, so we will add 2 at M[4][3] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
147
Course Code/Title:CS3302/Design Analysis of Algorithms
4 0 0 0 2
When i = 4, W = 4
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 4. The item with a weight 4 can be put in the
knapsack and the profit corresponding to the weight 4 is 3, so we will add 3 at M[4][4] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0 0 0 2 3
When i = 4, W = 5
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 5. The item with a weight 4 can be put in the
knapsack and the profit corresponding to the weight 4 is 3, so we will add 3 at M[4][5] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0 0 0 2 3 3
When i = 4, W = 6
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 6. In this case, we can put the items in the
knapsack either of weight 3, 4, 5 or 6 but the profit, i.e., 4 corresponding to the weight 6 is highest among
all the items; therefore, we add 4 at M[4][6] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
148
Course Code/Title:CS3302/Design Analysis of Algorithms
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 1 3 3 3 5 5
4 0 0 0 2 3 3 4
When i = 4, W = 7
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 7. Here, if we add two items of weights 3 and 4
then it will produce the maximum profit, i.e., (2 + 3) equals to 5, so we add 5 at M[4][7] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2 3 3 3 5 5
4 0 0 0 2 3 3 4 5
When i = 4, W = 8
The weight corresponding to the value 4 is 6, i.e., w4 = 6. Since we have four items in the set of weights 3,
4, 5, and 6 respectively, and the weight of the knapsack is 8. Here, if we add two items of weights 3 and 4
then it will produce the maximum profit, i.e., (2 + 3) equals to 5, so we add 5 at M[4][8] shown as below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2 3 3 3 5 5
4 0 0 0 2 3 3 4 5 5
As we can observe in the above table that 5 is the maximum profit among all the entries. The pointer points
to the last row and the last column having 5 value. Now we will compare 5 value with the previous row; if
the previous row, i.e., i = 3 contains the same value 5 then the pointer will shift upwards. Since the previous
row contains the value 5 so the pointer will be shifted upwards as shown in the below table:
149
Course Code/Title:CS3302/Design Analysis of Algorithms
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2 3 3 3 5 5
4 0 0 0 2 3 3 4 5 5
Again, we will compare the value 5 from the above row, i.e., i = 2. Since the above row contains the value
5 so the pointer will again be shifted upwards as shown in the below table:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2 3 3 3 5 5
4 0 0 0 2 3 3 4 5 5
Again, we will compare the value 5 from the above row, i.e., i = 1. Since the above row does not contain
the same value so we will consider the row i=1, and the weight corresponding to the row is 4. Therefore,
we have selected the weight 4 and we have rejected the weights 5 and 6 shown below:
x = { 1, 0, 0}
The profit corresponding to the weight is 3. Therefore, the remaining profit is (5 - 3) equals to 2. Now we
will compare this value 2 with the row i = 2. Since the row (i = 1) contains the value 2; therefore, the pointer
shifted upwards shown below:
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 0 0 2 2 2 2 2 2
2 0 0 0 2 3 3 3 5 5
3 0 0 0 2 3 3 3 5 5
150
Course Code/Title:CS3302/Design Analysis of Algorithms
4 0 0 0 2 3 3 4 5 5
Again we compare the value 2 with a above row, i.e., i = 1. Since the row i =0 does not contain the value
2, so row i = 1 will be selected and the weight corresponding to the i = 1 is 3 shown below:
X = {1, 1, 0, 0}
The profit corresponding to the weight is 2. Therefore, the remaining profit is 0. We compare 0 value with
the above row. Since the above row contains a 0 value but the profit corresponding to this row is 0. In this
problem, two weights are selected, i.e., 3 and 4 to maximize the profit.
151
Course Code/Title:CS3302/Design Analysis of Algorithms
UNIT IV
STATE SPACE SEARCH TREE AND BACKTRACKING
N-queen Problem
N-Queens problem is to place n-queens in such a manner on an NxN chessboard that no queen’s attack
eachother by being in the same row, column or diagonal.
It can be seen that for n=1 ,the problem has a trivial solution ,and no solution exists for n=2 and n=3.So
first we will consider the 4 queens problem and then generate it to n - queens problem.
Given a 4x4 chessboard and number the rows and column of the chessboard 1 through 4.
Since, we have to place 4 queens such as q1q2q3and q4on the chessboard, such that no two queens
attack each other .In such a conditional each queen must be placed on a different row,i.e.,we put queen
"i" on row "i."
Now, we place queen q1 in the very first acceptable position (1, 1). Next, we put queen q 2 so that both
these queens do not attack each other. We find that if we place q2 in column 1 and 2, then the dead end
is encountered. Thus the first acceptable position for q2 in column 3, i.e. (2, 3) but then no position is
left for placing queen 'q3' safely. So we backtrack one step and place the queen 'q 2' in (2, 4), the next
best possible solution. Then we obtain the position for placing 'q3' which is (3, 2). But later this position
also leads to a dead end, and no place is found where 'q4' can be placed safely. Then we have to
backtrack till 'q1' and place it to (1, 2) and then all other queens are placed safely by moving q2 to (2,
4), q3 to (3, 1) and q4 to (4, 3). That is, we get the solution (2, 4, 1, 3). This is one possible solution
for the 4-queens problem. For another possible solution, the whole method is repeated for all partial
solutions. The other solutions for 4 - queens problems is (3, 1, 4, 2) i.e.
152
Course Code/Title:CS3302/Design Analysis of Algorithms
Fig shows the complete state space for 4-queens problem .But we can use backtracking method
to generate the necessary node and stop if the next node violates the rule, i.e., if two queens are
attacking.
153
Course Code/Title:CS3302/Design Analysis of Algorithms
3. Then they are on same diagonal only if (i-j)= k-lori+ j=k +l.
154
Course Code/Title:CS3302/Design Analysis of Algorithms
6. Therefore, two queens lie on the duplicate diagonal if and only if |j-l|=|i-k|
Place (k, i) returns a Boolean value that is true if the kth queen can be placed in column i. It tests
both whether i is distinct from all previous costs x1, x2,... xk-1 and whether there is no other
queen on the same diagonal.
Using place, we give a precise solution to then n-queens problem.
Place (k, i)
{
For j←1tok- 1
Do if (x[j]=i)
Or (Absx[j]) -i)=(Abs(j- k))
Then return false;
Return true;
}
Place(k,i)return true if a queen can be placed in the k th row and it h column otherwise return is
false. x [] is a global array whose final k - 1 values have been set. Abs (r) returns the absolute
value of r.
1. N-Queens(k,n)
2. {
3. Fori←1ton
4. doifPlace(k,i)then5.
{
6. x[k]←i;
7. if(k==n)then
8. write(x[1 ... n));
9. else
10. N- Queens(k+1, n);
11. }
12.}
Hamiltonian Circuit
The Hamiltonian cycle is the cycle in the graph which visits all the vertices in graph exactly
once and terminates at the starting node. It may not include all the edges
The Hamiltonian cycle problem is the problem offinding a Hamiltonian cycle in a
graph if there exists any such cycle.
The input to the problem is an undirected, connected graph. For the graph shown in
Figure (a), a path A–B– E– D–C–A forms a Hamiltonian cycle. It visits all the vertices
155
Course Code/Title:CS3302/Design Analysis of Algorithms
exactly once, but does not visit the edges <B, D>.
156
Course Code/Title:CS3302/Design Analysis of Algorithms
V[i] ← j
HAMILTONIAN(i+1)
j←j+1
end end
end
function
FEASIBL
E(i)
flag←1
for
j ←1toi –1
do
if
Adjacent(Vi,Vj)
then
flag←
0 end
end
if
Adjacent(Vi,Vi-1)
then
flag←
1 else
flag←
0 end
return
flag
Complexity Analysis
Looking at the state space graph, in worst case, total number of nodes in tree would be, T(n) = 1 + (n – 1)
+ (n – 1)2 + (n – 1)3 + … + (n – 1)n–1
=frac(n−1)n–1n–2 T(n)=O(nn).Thus, the Hamiltonian cycle algorithm runs in
exponential time.
Example: Find the Hamiltonian cycle by using the backtracking approach for a given graph.
157
Course Code/Title:CS3302/Design Analysis of Algorithms
The backtracking approach uses a state-space tree to check if there exists a Hamiltonian cycle in the
graph. Figure (g) shows the simulation of the Hamiltonian cycle algorithm. For simplicity, we have
not explored all possible paths, the concept is self-explanatory. It is not possible to include all the
paths in the graph, so few of the successful and unsuccessful paths are traced in the graph. Black nodes
indicate the Hamiltonian cycle.
Subset SumProblem
Sum of Sub sets Problem :Given a set of positive integers ,find the combination of numbers that
sum to given value M.
Sumofsubsetsproblemisanalogoustotheknapsackproblem.TheKnapsackProblemtriestofillthe
knapsack using a given set of items to maximize the profit. Items are selected in such a way that
the total weight in the knapsack does not exceed the capacity of the knapsack. The inequality
158
Course Code/Title:CS3302/Design Analysis of Algorithms
condition in the knapsack problem is replaced by equality in the sum of subsets problem.
Given the set of n positive integers, W = {w1, w2, …, wn}, and given a positive integer M,
the sum of the subset problem can be formulated as follows(where wi and M correspond to item
weights and knapsack capacity in the knapsack problem):
Where,
Numbers are sorted in ascending order, such that w1< w2< w3< …. < wn. The solution is often
represented using the solution vector X. If the it h item is included, set xi to 1 else set it to 0. In
each iteration, one item is tested .If the inclusion of an item does not violet the constraint of the
problem, add it. Otherwise, backtrack, remove the previously added item ,and continue the same
procedure for all remaining items.
The solution is easily described by the state space tree. Each left edge denotes the inclusion of wi and
the right edge denotes the exclusion of wi. Any path from the root to the leaf forms a subset. A state-
space tree for n = 3 is demonstrated in Fig. (a).
159
Course Code/Title:CS3302/Design Analysis of Algorithms
Examples
160
Course Code/Title:CS3302/Design Analysis of Algorithms
Graph Colouring
In this problem, an undirected graph is given. There is also provided m colors. The problem is to
find if itis possible to assign nodes with m different colors, such that not wo adjacent vertices of the
graph are of the same colors. If the solution exists, then display which color is assigned on which
vertex.
Starting from vertex0, we will try to assign colors one by one to different nodes. But before
assigning, we have to check whether the color is safe or not. A color is not safe whether adjacent
vertices are containing the same color.
Input and Output Input: The adjacency matrix of a graph G (V,E) and an integer m , which
indicates the maximum number of colors that can be used.
Algorithm
isValid(vertex,colorList,col)
Input−Vertex,colorListtocheck,and color, which is trying to
assign. Output−True if the color assigning is valid,
otherwise false.
Begin
161
Course Code/Title:CS3302/Design Analysis of Algorithms
For all vertices v of the graph, do if there is an edge between v and i, and
col=color List[i],then return false
done return true
End
Graph Coloring(colors,colorList,vertex) Input−Most possible colors, the list for which vertices
are colored with which color ,and the starting vertex. Output−True,when colors are
assigned, otherwise false.
Begin
If all vertices are checked,
then return true
For all colors col from available
colors, do if isValid(vertex, color,
col), then
Add col to the color List for vertex
if graph Coloring(colors,colorList,vertex+1)=true, then
return true remove color for
vertex
done return
false
End
Branch and Bound
Solving15puzzle Problem(LCBB)
The problem c insist of 15 numbered (0-15) tiles on a square box with16 tiles(one tile is blank or
empty). The objective of this problem is to change the arrangement of initial node to goal node by
using series of legal moves.
The Initial and Goal node arrangement is shown by following figure.
162
Course Code/Title:CS3302/Design Analysis of Algorithms
1 2 4 15 1 2 3 4
2 5 12 5 6 7 8
7 6 11 14 9 10 11 12
8 9 10 13 13 14 15
In initial node four moves are possible. User can move any one of the tile like 2, or 3, or5, or 6 to the
empty tile. From this we have four possibilities to move from initial node.
The legal moves are for adjacent tile number is left, right, up, down, ones at a time.
Each and every move creates a new arrangement, and this arrangement is called state of puzzle
problem. By using different states, a state space tree diagram is created, in which edges are labeled
according to the direction in which the empty space moves.
The state space tree is very large because it can be 16! Different arrangements. In state space
tree, nodes are numbered as per the level. In each level we must calculate the value or cost of
each node by using given formula:
C(x)=f(x)+g(x), f(x)is length of path from root
or initial node to node x,
g(x)is estimated length of path from x do w n ward to the goal node. Number of nonblank
tile not in their correct position.
C(x)< Infinity .(initially set bound).
Each time node with smallest cost is selected for further expansion towards goal node.
This node become the e-node.
State Space tree with node cost is shown diagram.
163
Course Code/Title:CS3302/Design Analysis of Algorithms
Assignment Problem
Problem Statement
Let’s first define a job assignment problem. In a standard version of a job
assignment problem, there can be jobs and workers. To keep it simple,
we’re taking jobs and workers in our example:
We can assign any of the available jobs to any worker with the condition that if a job is
assigned to a worker, the other workers can’t take that particular job. We should also
notice that each job has some cost associated with it, and it differs from one worker to
another.
Here the main aim is to complete all the jobs by assigning one job to each worker in such a
way that the sum of the cost of all the jobs should be minimized.
Branch and Bound Algorithm Pseudo code
Now let’s discuss how to solve the job assignment problem using a branch and
bound algorithm. Let’s see the pseudocode first:
164
Course Code/Title:CS3302/Design Analysis of Algorithms
Here,is the input cost matrix that contains information like the number of available jobs, a
list of available workers, and the associated cost for each job. The function Min Cost()
maintains a list of active nodes. The function Least cost()calculates the minimum cost of the
active node at each level of the tree. After finding the node with minimum cost, we remove the
node from the list of active nodes and return it.
We’re using the add() function in the pseudocode, which calculates the cost of a
particular node and adds it to the list of active nodes.
In the search space tree, each node contains some information, such as cost, a total number of
jobs, as well as a total number of workers.
Now let’s run the algorithm on the sample example we created:
165
Course Code/Title:CS3302/Design Analysis of Algorithms
Advantages
In a branch and bound algorithm, we don’t explore all the nodes in the tree. That’s
why the time complexity of the branch and bound algorithm is less when compared
with other algorithms.
If the problem is not large and if we can do the branching in a reasonable amount of time,
it finds an optimal solution for a given problem.
Thebranchandboundalgorithmfindaminimalpathtoreachtheoptimalsolutionforagiven problem. It
doesn’t repeat nodes while exploring the tree.
Disadvantages
The branch and bound algorithm are time-consuming. Depending on the size of the given
problem, the number of nodes in the tree can be too large in the worst case.
Problem Statement
We are a given a set of n objects which have each have a value vi and a weight wi. The
objective of the0/1Knapsack problem is to find a subset of objects such that the total value
is maximized, and
The sum of weights of the objects does not exceed a given threshold W. An important
condition here is that one can either take the entire object or leave it. It is not possible to
take a fraction of the object.
Consider an example where n=4, and the values are given by {10,12,12, 18}and the weights
given by {2, 4, 6, 9}. The maximum weight is given by W = 15. Here, the solution to the
problem will be including the first, third and the fourth objects.
166
Course Code/Title:CS3302/Design Analysis of Algorithms
If the cost function for a given node is greater than the upper bound, then the node need
not be explored further. Hence, we can kill this node. Otherwise, calculate the upper
bound forth is node. If this value is less than U, then replace the value of U with this
value. Then, kill all unexplored nodes which have cost function greater than this value.
Thenextnodetobecheckedafterreachingallnodesinaparticularlevelwillbe the one
with the least cost function value among the unexplored nodes.
While including an object, one needs to check whether the adding the object
crossed the threshold. If it does, one has reached the terminal point in that
branch, and all the succeeding objects will not be included.
Solving an Example
Consider the problem with n=4, V ={10,10,12, 18}, w={2,4,6,9}and W=
15.Here,wecalculate the initital upper bound to be U = 10 + 10 + 12 = 32. Note that the 4th
object cannot be included here, since that would exceed W. For the cost, we add 3/9 th of
the final value, and hence the cost function is
38. Remember to negate the values after calculation before comparison.
After calculating the cost at each node, kill nodes that do not need exploring. Hence, the
final state space tree will be as follows (Here, the number of the node denotes the order in
which the state space tree was explored):
167
Course Code/Title:CS3302/Design Analysis of Algorithms
Note here that node 3 and node 5 have been killed after updating U at node 7. Also, node 6 is
not explored further, since adding any more weight exceeds the threshold. At the end, only
nodes 6 and 8remain. Since the value of U is less for node 8,we select this node. Hence the
solution is{1,1,0,1}, and we can see here that the total weight is exactly equal to the threshold
value in this case.
168
Course Code/Title:CS3302/Design Analysis of Algorithms
weighted directed edges represents direction and distance between two cities.
1. Initially, graph is represented by cost matrix C, where
Cij=cost of edge, if there is a direct path from city i to
city j Cij=∞, if there is no direct path from city i to city
j.
2. Convert cost matrix to reduced matrix by subtracting minimum values from
appropriate rows and columns, such that each row and column contains at least one
zero entry.
3. Find cost of reduced matrix. Cost is given by summation of subtracted amount
from the cost matrix to convert it in to reduce matrix.
4. Prepare state space tree for the reduce matrix
5. Find least cost valued node A(i.e.E-node),by computing reduced cost node
matrix with every remaining node.
6. If<i,j>edge is to be included, the end following:
(a) Set all values in row I and all values in column j of A to∞
(b) Set A[j,1]= ∞
(c) Reduce Aagain, except rows and columns having all ∞entries.
7. Compute the cost of newly created
reduced matrix as, Cost=L + Cost(i, j) + r
Where ,List cost of original reduced cost
matrix and ris A[i,j].
8. If all nodes are not visited then go
to step 4. Reduction procedure is
described below :
Raw Reduction:
Matrix Mis called reduced matrix if each of its row and column has at least one
zero entry or entire row or entire column has ∞ value. Let M represents the
distance matrix of 5 cities. M can be reduced as follow:
MRowRed={Mij– min{Mij|1≤ j≤n,and Mij< ∞}}
Consider the following distance matrix:
Find the minimum element from each row and subtract it from each cell of matrix.
169
Course Code/Title:CS3302/Design Analysis of Algorithms
Row reduction cost is the summation of all the values subtracted from
each rows: Row reduction cost (M) = 10 + 2 + 2 + 3 + 4 = 21
Column reduction:
Matrix MRowRed is row reduced but not the column reduced. Matrix is called column reduced
if each of its column has at least one zero entry or all ∞ entries.
MColRed={Mji–min{Mji|1≤j≤n, and Mji<∞ }} To reduced above matrix, we will find the
minimum element from each column and subtract it from each cell of matrix.
170
Course Code/Title:CS3302/Design Analysis of Algorithms
Each row and column of MColRed has at least one zero entry, so this matrix is reduced
matrix. Column reduction cost (M) = 1 + 0 + 3 + 0 + 0 = 4 State space tree for 5 city problem
is depictedin Fig.6.6.1.Number with in circle indicates the order in which the node is
generated, and number of edge indicates the city being visited.
Example
Example: Find the solution of following travelling sales man problem using branch and bound
method.
Solution:
The procedure for dynamic reduction is as follow :
Draw state space tree with optimal reduction cost at root node.
Derive cost of path from node I to j by setting all entries in ithrow and jth column as∞. Set
M[j][i]
=∞
Cost of corresponding node N for path I to j is summation of optimal cost + reduction cost+
M[j][i]
After exploring all nodes at level i,set node with minimum cost as E
node and repeat the procedure until all nodes are visited.
Given matrix is not reduced. Inorder to find reduced matrix of it, we will first
find the row reduced matrix followed by column reduced matrix if needed. We
can find row reduced matrix by subtracting minimum element of each row
from each element of corresponding row. Procedure is described below:
Reduce above cost matrix by subtracting minimum value from each row and column.
171
Course Code/Title:CS3302/Design Analysis of Algorithms
M‘1
is not reduced matrix. Reduce it subtracting minimum value from corresponding column.
Doing this we get,
Cost of M1=C(1)
=Row reduction cost + Column reduction cost
=(10+2+2+3+4)+(1+3)=25
This means all tours in graph has length at least25.This is the optimal cost of the path.
State space tree
172
Course Code/Title:CS3302/Design Analysis of Algorithms
M2 is already reduced.
Cost of node 2 :
C(2)=C(1)+Reduction cost
+M1[1][2]
=25+0+10=35
Select edge1-3 Set
M1[1][]=M1[][3]=∞ Set
M1 [3][1] = ∞
Reduce the resultant matrix if required.
Cost of node 3:
C(3)=C(1)+Reduction cost
+M1[1][3]
=25+11+17=53
Select edge1-4:
Set M1[1][]=M1[][4]=∞ Set
M1 [4][1] = ∞
Reduce resultant matrix if required.
Matrix M4 is already
reduced. Cost of node 4:
173
Course Code/Title:CS3302/Design Analysis of Algorithms
Cost of node 5:
C(5)=C(1)+reduction cost +M1[1][5]
=25+5+1=31
State space diagram:
Node 4 has minimum cost for path 1-4.We can go to vertex 2,3 or 5.Let’s explore all three nodes.
Select path1-4-2:(Addedge4-2)
SetM4[1][]=M4[4][]=M4[] [2]=∞ Set
M4 [2] [1]=∞
Reduce resultant matrix if required.
174
Course Code/Title:CS3302/Design Analysis of Algorithms
M‘7
Cost of node 7:
C(7)=C(4)+Reduction cost
+M4[4][3]
=25+2+11+12=50
Select edge4-5(Path1-4-5):
175
Course Code/Title:CS3302/Design Analysis of Algorithms
Path1-4-2leads to minimum cost. Let’s find the cost for two possible paths.
Cost of node 9:
C(9)=C(6)+Reduction cost
+M6[2][3]
=28+11+2+11=52
Addedge2-5(Path1-4-2-5):
SetM6[1][]= M6[4][]=M6[2][]=M6[][5]=∞
Set M6 [5][1] = ∞
Reduce resultant matrix if required.
176
Course Code/Title:CS3302/Design Analysis of Algorithms
Add edge5-3(Path1-4-2-5-3):
177
Course Code/Title:CS3302/Design Analysis of Algorithms
So we can select any of the edge.Thus the final path includes the edges<3,1>,<5,3>,<1,4>,<4,2>,
<2,5>,that forms the path1– 4–2 –5– 3–1.This path has cost of 28.
178
Course Code/Title:CS3302/Design Analysis of Algorithms
UNIT 5
V NP-COMPLETE AND APPROXIMATION ALGORITHM
179
Course Code/Title:CS3302/Design Analysis of Algorithms
function, the taskis to find the values of the variables that optimize the objective function
subject to the constraints. Algorithms like the simplex method can solve this problem in
polynomial time.
5. Graph coloring: Given an undirected graph G, the task is to assign a color to each node
such that no two adjacent nodes have the same color ,using as few colors as possible.
The greedy algorithm can solve this problem in O(n^2)time complexity, where n is the
number of nodes in the graph.
These problems are considered tractable because algorithms exist that can solve the min
polynomial l time complexity, which means that the time required to solve them grows no
faster than a polynomial function of the input size.
1. Linearsearch: Given a list of n items, the task is to find a specific item in the
list. The time complexity of linear search is O(n), which h is a polynomial
function of the input size.
180
Course Code/Title:CS3302/Design Analysis of Algorithms
2. Bubblesort: Given a list of n items, the task is to sort the min ascending order. The time
complexity of bubble sort is O(n^2), which is also a polynomial function of the input
size.
3. Shortest path in a graph: Given a graph G and two nodes s and t, the task is to find
the shortest path between s and t .Algorithms like Dijkstra's algorithm and the A*
algorithm can solve this problem in O(m+nlogn) time complexity, which is a
polynomial function of the input size.
4. Maximum flow in a network: Given a network with a source node and a sink node,
and capacities on the edges, thetaskis tofindthe maximumflowfromthesourcetothe
sink. The Ford-Fulkerson algorithm can solve this problem in O(mf),where m is the
number of edges in the network and f is the maximum flow, which is also a
polynomial function of the input size.
5. Linear programming: Given a system of linear constraints and a linear objective
function, the task is to find the values of the variables that optimize the objective
function subject to the constraints. Algorithms like the simplex method can solve this
problem in polynomial time.
P(Polynomial)problems
P problems refer to problems where an algorithm would take a polynomial amount of
time to solve, or where Big-O is a polynomial (i.e.O(1),O(n),O(n²),etc). These are
problems that would be considered ‘easy’ to solve, and thus do not generally have
immense run times.
NP(Non-deterministicPolynomial)Problems
NP problems were a little harder forme to understand, but I think this is what they are.
Interms of solving a NP problem, the run-time would not be polynomial. It would be
something like O(n!) or something much larger.
NP-Hard Problems
A problem is classified as NP-Hard when an algorithm for solving it can be translated
to solve an Zy NP problem. Then we can say, this problem is atleast as hard as any
NP problem, but it could be much harder or more complex.
181
Course Code/Title:CS3302/Design Analysis of Algorithms
NP-Complete Problems
NP-Complete problems are problems that live in both the NP and NP-Hard
classes. This means that NP-Complete problems can be verified in polynomial
time and that any NP problem can be reduced to this problem in polynomial time.
The simplest approximate approach to the bin packing problem is the Next-Fit (NF)
algorithm which is explained later in this article. The first item is assigned to bin 1.
Items 2,...,n are then considered by increasing indices: each item is assigned to the
current bin, if it fits; otherwise, it is assigned to a new bin, which becomes the current
one.
VisualNRepresentation
Let us consider the same example as used above and bins of size 1
182
Course Code/Title:CS3302/Design Analysis of Algorithms
The Next fit solution (NF(I)) forth is instance I would be- Considering 0.5 size d item
first, we can place it in the first bin
Moving onto the 0.7 size d item, we cannot place it in the first bin. Hence we place it in a new
bin.
Moving on to the 0.5 sized item, we cannot place it in the current bin. Hence we place it in a new
bin.
Moving on to the 0.2 sized item, we can place it in the current (third bin)
Thus we need 6 bins as opposed to the 4 bins of the optimal solution. Thus we can see
that this algorithm is not very efficient.
Analyzing the approximation ratio of Next-Fit algorithm
The time complexity of the algorithm is clearlyO(n). It is easy to prove that, for any
instance I of BPP, the solution value NF(I) provided by the algorithm satisfies the
bound
183
Course Code/Title:CS3302/Design Analysis of Algorithms
NF(I)<2z(I)
Where z(I) denotes the optimal solution value. Furthermore, there exist instances for
which the ratio NF(I)/z (I) is arbitrarily close to 2, i.e. the worst-case approximation
ratio of NFisr(NF)
=2.
Psuedo code
NEXTFIT(size[],n,c)
size[] is the array containg the sizes of the items, n is the number of items and c is the
capacity of the bin
{
Initialize result(Count of bins) and remaining capacity in current bin.res=0
bin_rem=c
Place items one by one
for(inti=0;i <n;i++){
//If this item can't fit in current
bin if (size[i] > bin_rem) {
Use a new bin
res++
bin_rem=c-size[i]
}
else
bin_rem-=size[i];
}
returnres;
}
2) FirstFit algorithm
A better algorithm, First-Fit (FF), considers the items according to increasing indices and
assign seach item to the lowest indexed initialized bin in to which it fits; only when the current
item cannot fit in to any initialized bin, is a new bin introduced
VisualRepresentation
Let us consider the same example as used above and bin s of size 1
184
Course Code/Title:CS3302/Design Analysis of Algorithms
Considering0.5sizeditemfirst,wecanplaceitinthefirstbin
Movingontothe0.7sizeditem,wecannotplaceitinthefirstbin.Henceweplaceitinanewbin.
Movingontothe0.5sizeditem,wecanplaceitinthefirstbin.
Movingontothe0.2sizeditem,wecanplaceitinthefirstbin,wecheckwiththesecondbinand
we can place it there.
Movingontothe0.4sizeditem,wecannotplaceitinanyexistingbin.Henceweplaceitinanewbin.
Similarly,placingalltheotheritemsfollowingtheFirst-Fitalgorithmweget-
185
Course Code/Title:CS3302/Design Analysis of Algorithms
Thus we need 5 bins as opposed to the 4 bins of the optimal solution but is much more
efficient than Next-Fit algorithm.
AnalyzingtheapproximationratioofNext-Fitalgorithm
If FF(I)is theFirst-fit implementation for Iinstance and z(I)is the most optimal solution, then:
ItcanbeseenthattheFirstFitneverusesmorethan1.7*z(I)bins.SoFirst-
FitisbetterthanNextFit in terms of upper bound on number of bins.
Psuedocode
FIRSTFIT(size[],n,c)
{
size[]isthearraycontaingthesizesoftheitems,nisthenumberofitemsandcisthecapacityoft
he bin
/Initializeresult(Countofbins)
res=0;
Createanarraytostoreremainingspaceinbinstherecanbeatmostnbinsbin_rem[n];
Plaeitemsonebyone
for(inti=0;i<n;i++){
Findthefirstbinthatcanaccommodateweight[i]intj;
for(j=0;j <res;j++){
if (bin_rem[j] >= size[i]) {
bin_rem[j]=bin_rem[j]-
size[i]; break;
}
}
Ifnobincouldaccommodatesize[i]
if (j == res) {
186
Course Code/Title:CS3302/Design Analysis of Algorithms
bin_rem[res]=c-
size[i]; res++;
}
}
returnres;
}
3) BestFitAlgorithm
The next algorithm,Best-Fit(BF), is obtained from FF by assigning the current item to the
feasible bin (if any) having the smallest residual capacity (breaking ties in favor of the lowest
indexed bin).
Simply put,the idea is to places the next item in the tightes tspot.That is,put it in the
bin so that the smallest empty space is left.
VisualRepresentation
Letusconsiderthesameexampleasusedaboveandbinsofsize1
Movingontothe0.7sizeditem,wecannotplaceitinthefirstbin.Henceweplaceitinanewbin.
187
Course Code/Title:CS3302/Design Analysis of Algorithms
Moving on to the 0.5sized item,we can place it in the first bin tightly.
Moving on to the 0.2 sized item,we cannot place it in the first bin but we can place it in second
bin tightly.
Moving on to the 0.4 sized item,we cannot place it in any existing bin.Hence we place it in a new
bin.
Similarly,placing all the other items following the First-Fit algorithm we get-
Thus we need 5 bins as opposed to the 4 bins of the optimal solution but is much more efficient than Next-
Fit algorithm.
Analyzing the approximation ratio of Best-Fit algorithm
It can be noted that Best-Fit(BF), is obtained from FF by assigning the current item
to the feasible bin (if any) having the smallest residual capacity (breaking ties in
favour of the lowest indexed bin). BF satisfies the same worst-case bounds as FF
AnalysisOfupper-boundofBest-Fitalgorithm
If z(I) is the optimal number of bins, then BestFit n ever use s more than 2*z(I)-2 bins.
So Best Fit is same as Next Fit in terms of upper bound on number of bins.
188
Course Code/Title:CS3302/Design Analysis of Algorithms
Psuedo code
BEST FIT(size[],n,c)
{
size[] is the array containg the size s of the items, n is the number of item s and c is
the capacity of the bin
Initialize result(Count of bins)res
=0;
Initialize minimum space left and index of best bin int min = c + 1, bi = 0;
for(j=0;j<res;j++){
if(bin_rem[j]>=size[i]&&bin_rem[j]-
size[i]<min){bi=j; min=bin_rem[j]-size[i];
}
}
189
Course Code/Title:CS3302/Design Analysis of Algorithms
We first sort the array of item s in decreasing size by weight and apply first-fit
algorithm as discussed above
Algorithm
Read the input s of items
Sort the array of item s in decreasing order by their sizes
Apply First-Fit algorithm
Visual Representation
Let us consider the same example as used above and bin s of size 1
We then select 0.6 sized item. We cannot place it in bin 1.So, we place it in bin 2
We then select 0.5 sized item. We cannot place it in any existing. So, we place it in bin 3
190
Course Code/Title:CS3302/Design Analysis of Algorithms
Thus only 4 bins are required which his the same as the optimal solution.
We first sort the array of items in decreasing size by weight and apply Best-fit
algorithm as discussed above
Algorithm
Read the inputs of items
Sort the array of items in decreasing order by their sizes
Apply Next-Fit algorithm
Visual Representation
Let us consider the same example as used above and bins of size 1
191
Course Code/Title:CS3302/Design Analysis of Algorithms
We then select 0.6 sized item. We cannot place it in bin 1. So, we place it in bin 2
We then select 0.5 sized item. We cannot place it in any existing. So, we place it in bin 3
Thus only 4 bins are required which is the same as the optimal solution.
Approximation Algorithms for the Traveling Salesman Problem
We solved the traveling sales man problem by exhaustive search in Section3.4,
mentioned its decision version as one of the most well-known NP-complete problems
in Section 11.3, and saw how its instances can be solved by a branch-and-bound
algorithm in Section 12.2. Here, we consider several approximation algorithms, a
small sample of dozens of such algorithms suggested over the years for this famous
problem.
But first let us answer the question of whether we should hope to find a polynomial-
time approximation algorithm with a finite performance ratio on all instances of the
192
Course Code/Title:CS3302/Design Analysis of Algorithms
Nearest-neighbour algorithm
The following well-known greedy algorithm is based on the nearest-neighbor
heuristic: always go next to the nearest unvisited city.
Step1 Choose an arbitrary city as the start.
Step2 Repeat the following operation until all the cities have beenvisited: go to the
unvisited city nearest the one visited last (ties can be broken arbitrarily).
Step3 Return to the starting city.
EXAMPLE1 For the instance represented by the graph in Figure12.10, with a as the
starting vertex, the nearest-neighbor algorithm yields the tour (Hamiltonian
circuit) sa:a−b−c−d−a of length 10.
Unfortunately, except for its simplicity, not many good things can be said about the
nearest- neighbor algorithm. In particular, nothing can be said in general about the
193
Course Code/Title:CS3302/Design Analysis of Algorithms
Which can be made as large as we wish by choosing an appropriately large value of w. Hence,
RA=
∞ for this algorithm(as it should be according to Theorem1).
Twice-around-the-tree algorithm
Step1 Construct a minimum spanning tree of the graph corresponding to a given
instance of the traveling salesman problem.
Step2Starting at an arbitrary vertex, perform a walk around the minimum spanning
tree recording all the vertices passed by. (This can be done by a DFS traversal.)
Step3Scan the vertex list obtained in Step2 and eliminate from it all repeated
occurrences of the same vertex except the starting on e at the end of the list.(This step
is equivalent to making shortcuts in the walk.) The vertices remaining on the list will
form a Hamiltonian circuit, which is the output of the algorithm.
194
Course Code/Title:CS3302/Design Analysis of Algorithms
1≡1(modn)OR
an-1%n=1
Example: Since 5 is prime,
24≡1(mod5)[or24%5=1],
34≡1(mod5)and44≡1(mod5)
Since7isprime,26≡ 1(mod7),
36≡1(mod7),46≡1(mod7)
56≡1(mod7)and66≡1(mod7)
Algorithm
1) Repeat following k times:
2) Return true[probablyprime].
Unlike merge sort, we don’t need to merge the two sort e d arrays. Thus Quick sort
require s lesser auxiliary space than Merge Sort, which is why it is often preferred to
Merge Sort.
Using a randomly generated pivot we can further improve the time complexity of QuickSort.
Algorithm for random pivoting
195
Course Code/Title:CS3302/Design Analysis of Algorithms
partition(arr[],lo,hi)
pivot=arr[hi]
i = lo //place for
swapping for j := lo to hi
– 1 do
if arr[j] <= pivot then
swaparr[i]witharr[j]i
=i +1
swaparr[i]witharr[hi]retur
ni
partition_r(arr[],lo,hi)
r=RandomNumberfromlotohiSw
ap arr[r] and arr[hi]
returnpartition(arr,lo,hi)
quicksort(arr[],lo,hi)
iflo<hi
p=partition_r(arr,lo,hi)
quicksort(arr, lo , p-1)
quicksort(arr, p+1, hi)
Finding k th smallest element
Problem Description:Given an arrayA[] of n elements and a positive integer K, find
the Kth smallest element in the array. It is given that all array elements are distinct.
For Example:
Input:A[]={10,3,6,9,2,4,15,23},K=4
Output:6
Input:A[]={5,-8,10,37,101,2,9},K=6
Output:37
Quick-Select:Approach similar to quicksort
This approach is similar to the quick sort algorithm where we use the partition on the
input array recursively. But unlike quicksort, which processes both sides of the array
recursively, this algorithm works on only one side of the partition. We recur for either
the left or right side according to the position of pivot.
Solution Steps
1. Partition the arrayA[left..right]into two subarrays A[left..pos] and A[pos+1..right]
such that each element of A[left .. pos] is less than each element of A[pos + 1 .. right].
2. Computes the number of elements in the subarrayA[left..pos]i.e.count=pos-left+1
196
Course Code/Title:CS3302/Design Analysis of Algorithms
197