Design and Analysis of Algorithms Dr. N. Subhash Chandra: Course Objectives
Design and Analysis of Algorithms Dr. N. Subhash Chandra: Course Objectives
Design and Analysis of Algorithms Dr. N. Subhash Chandra: Course Objectives
Course Outcomes
CO 2: Choose the appropriate data structure and algorithms design method for a specified
application.
Example:
The greatest common divisor(GCD) of two nonnegative integers m and n (not-both-
zero,m<=n), denoted gcd(m, n), is defined as the largest integer that divides both m and n
evenly, i.e., with a remainder of zero.
Euclid’s algorithm is based on applying repeatedly the equality gcd(m, n) = gcd(n, m mod
n), where m mod n is the remainder of the division of m by n, until m mod n is equal to 0.
Since gcd(m,0) = m, the last value of m is also the greatest common divisor of the initial m
and n.
gcd(60, 24) can be computed as follows:gcd(60, 24) = gcd(24, 12) = gcd(12, 0) = 12.
Step 1 If n = 0, return the value of m as the answer and stop; otherwise, proceed to Step
2.
Step 2 Divide m by n and assign the value of the remainder to r.
Step 3 Assign the value of n to m and the value of r to n. Go to Step 1.
language
like C, C++, JAVA.
1. The transition from an algorithm to a program can be done either incorrectly
or very inefficiently. Implementing an algorithm correctly is necessary. The
Algorithm power should not reduced by inefficient implementation.
2. Standard tricks like computing a loop’s invariant (an expression that does not
change its value) outside the loop, collecting common subexpressions,
replacing expensive operations by cheap ones, selection of programming
language and so on should be known to the programmer.
3. Typically, such improvements can speed up a program only by a constant
factor, whereas a better algorithm can make a difference in running time by
orders of magnitude. But once an algorithm is selected, a 10–50% speedup
may be worth an effort.
4. It is very essential to write an optimized code (efficient code) to reduce the
burden of
5. compiler.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 3
Unit - 1
Year and Semester: IIyr &II Sem
A
Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr.N. Subhash Chandra, Professor of CSE
1 Algorithm Sum(a[],n) 0 - 0
2 { 0 - 0
3 S = 0.0; 1 1 1
5 s = s+a[i]; 1 n n
6 return s; 1 1 1
7 } 0 - 0
Definition:
Let f(n) and g(n) be asymptotically non-negative functions. We say
f (n) is Ω ( g ( n )) if there is a positive real constant c and a positive integer n0 such that
for every n >= n0 0 <= c * g (n ) <= f ( n).
(Or)
Ω ( g ( n )) = { f (n) | there exist positive constant c and a positive integer n0 such that 0
<= c * g (n ) <= f ( n) for all n >= n0 }
From the definition of Omega, there must exist c>0 and integer n0>0 such that 0 <= c*n
<= 5n-20 for all n>= n0
Dividing the inequality by n>0 we get: 0 <= c <= 5-20/n for all n>= n0.
20/n <= 20, and 20/n becomes smaller as n grows.
There are many choices here for c and n0.
Since c > 0, 5 – 20/n >0 and n0 >4
For example, if we choose c=4, then 5 – 20/n <= 4 and n0 >= 20
In this case we have a c>o and n0>0 such that 0 <= c*n <= 5n-20 for all n >=n0. So the
definition is satisfied and 5n-20 in Ω (n)
1 2
n 3n O(n 2 )
2
1 2
n 3n (n 2 )
2
From the definition there must exist c 0,and n0 0 such that
1
0 n 2 3n cn 2 for all n n0.
2
Dividing the inequality by n 2 0 we get :
1 3
0 c for all n n0.
2 n
Since 3 / n 0 for finite n, c 1/2.
Choosec 1 / 4.
1 3 1
So , and n0 12
2 n 4
There must exist c 0 and n0 0 such that
1
0 cn 2 n 2 3n for all n n0
2
Dividing by n 2 0 we get
1 3
0c .
2 n
1 3
Since c 0, 0 and n0 6.
2 N
Since 3 /n 0 for finite n, c 1/ 2. Choose c 1/4.
1 1 3
for all n 12.
4 2 n
So c 1/ 4 and n0 12.
Asymptotic o(Little-oh)
Definition: Let f (n) and g(n) be asymptotically non-negative functions. We say f ( n ) is
o ( g ( n)) if for every positive real constant c there exists a positive integer n0 such that
for all n>=n0
0 <= f(n) < c g (n ).
(Or)
o(g(n))={f(n): for any positive constant c >0, there exists a positive integer n0 > 0 such
that 0 <= f( n) < c g (n ) for all n >= n0 }
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 5
Unit - 1
Year and Semester: IIyr &II Sem
A
Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr.N. Subhash Chandra, Professor of CSE
Let us now look into how big-O bounds can be computed for
some common algorithms.
Example :
2n2 + 5n – n
) 2n2 + 5n – 6 = o (2n)
2n2 + 5n – 3
) 2n2 + 5n – 6 = o (n3)
2n2 + 5n – 2
) 2n2 + 5n – 2
)
2n2 + 5n – 2n + 5n –
2
Example:
If the first program takes 100n2 milliseconds and while the second
takes 5n3 milliseconds, then might not 5n3 program better than 100n2
program?
5 n3/100 n2 = n/20
for inputs n < 20, the program with running time 5n3 will be faster
than those the one with running time 100 n 2. Therefore, if the
program is to be run mainly on inputs of small size, we would indeed
prefer the program whose running time was O(n3)
However, as ‘n’ gets large, the ratio of the running times, which is
n/20, gets arbitrarily larger. Thus, as the size of the input increases,
the O(n3) program will take significantly more time than the O(n 2)
program. So it is always better to prefer a program whose running
time with the lower growth rate. The low growth rate function’s such
as O(n) or O(n log n) are always better.
Example:
This loop will run exactly n times, and because the inside of the loop
takes constant time, the total running time is proportional to n. We
write it as O(n). The actual number of instructions might be 50n,
while the running time might be 17n microseconds. It might even be
17n+3 microseconds because the loop needs some time to start up.
The big-O notation allows a multiplication factor (like 17) as well as an
additive factor (like 3). As long as it’s a linear function which is
proportional to n, the correct notation is O(n) and the code is said to
have linear running time.
Example:
Analysis for nested for loop
The outer for loop executes N times, while the inner loop executes n
times for every execution of the outer loop. That is, the inner loop
2
times. The assignment statement in the inner
loop takes constant time, so the running time of the code is O(n 2)
steps. This piece of code is said to have quadratic running time.
Example:
Analysis of matrix multiply
There are 3 nested for loops, each of which runs n times. The
innermost loop therefore executes n*n*n = n 3 times. The innermost
statement, which contains a scalar sum and product takes constant
O(1) time. So the algorithm overall takes O(n3) time.
The main body of the code for bubble sort looks something like this:
This looks like the double. The innermost statement, the if, takes O(1)
time. It doesn’t necessarily take the same time when the condition is
true as it does when it is false, but both times are bounded by a
constant. But there is an important difference here. The outer loop
executes n times, but the inner loop executes a number of times that
depends on i. The first time the inner for executes, it runs i = n-1
times. The second time it runs n-2 times, etc. The total number of
times the inner if statement executes is therefore:
The value of the sum is n(n-1)/2. So the running time of bubble sort is
O(n(n-1)/2), which is O((n2-n)/2). Using the rules for big-O given
earlier, this bound simplifies to O((n 2)/2) by ignoring a smaller term,
and to O(n2), by ignoring a constant factor. Thus, bubble sort is an
O(n2) algorithm.
3, 2, 1, 0
Since the second sequence decrements by 1 each time down to 0, its length
must be
log2 n + 1. It takes only constant time to do each test of binary
search, so the total running time is just the number of times that we
iterate, which is log2n + 1. So binary search is an O(log2 n) algorithm.
Since the base of the log doesn’t matter in an asymptotic bound, we
can write that binary search is O(log n).
4. The time to execute a loop is the sum, over all times around
the loop, the time to execute the body and the time to
evaluate the condition for termination (usually the latter is
O(1)). Often this time is, neglected constant factors, the
product of the number of times around the loop and the largest
possible time for one execution of the body, but we must
consider each loop separately to make sure.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 6
Unit - 1
Year and Semester: IIyr &II Sem
A
Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr.N. Subhash Chandra, Professor of CSE
A discrete random variable X is a function from a finite sample space S to the real numbers.
• Given such a function X we can define the probability density function for X as: f(x) =
Pr{X = x} where the little x is a real number.
The expected value of a random variable X is defined to be:
• The variance of X, Var[X] is defined to be: E[(X- E(X))2]= E[X2] -(E[X])2 • The standard
deviation of X, σX, is defined to be the (Var[X])1/2.
Lemma 1: Given a sample space S and an event A in S, let XA=I{A}. Then E[XA]=P{A}.
Proof: E[XA] = E[I{A}]
= 1*P{A}+ 0*P{A}
=P{A}.
Indicator random variables are more useful if we are dealing with more than one coin flip.
Let Xi be the indicator that indicates whether the result of the ith coin flip was a head.
Consider the random variable: X= ∑𝑛𝑖=1 𝑥𝑖
Then the expected number of head in n tosses is
1
E[X]=E[∑𝑛𝑖=1 𝑥𝑖 ]=∑𝑛𝑖=1 𝐸[𝑥𝑖 ]=∑𝑛𝑖=1 =n/2
2
We will now begin our investigation of randomized algorithms with a toy problem:
• You want to hire an office assistant from an employment agency.
• You want to interview candidates and determine if they are better than the current
assistant and if so replace the current assistant.
• You are going to eventually interview every candidate from a pool of n candidates.
• You want to always have the best person for this job, so you will replace an assistant with
a better one as soon as you are done the interview.
• However, there is a cost to fire and then hire someone.
• You want to know the expected price of following this strategy until all n candidates have
been interviewed.
Algorithm Hire-Assistant(n)
{
best := dummy candidate;
for i := 1 to n do
{
interview of candidate i ;
if (candidate i is better than best) then
{
best := i;
hire candidate i;
}
}
}
Assume that the candidates are presented in random order, then algorithm Hire-Assistant
has a hiring cost of O(ch*ln n)
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 7
Unit - 1
Year and Semester: IIyr &II Sem
A
Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr.N. Subhash Chandra, Professor of CSE
Worst-
O(min(|S|,k)
case O(1) O(1)
= O(n)
cost:
ci cˆi
i 1 i 1
for all n.
Thus, the total amortized costs provide an upper bound on the total true costs.
x i 0 A[i] 2i
k 1
INCREMENT(A)
1. i0
2. while i < length[A] and A[i] = 1
3. do A[i] 0 ⊳ reset a bit
4. ii+1
5. if i < length[A]
6. then A[i] 1 ⊳ set a bit
0 0 0 0 0 0 0
1 0 0 0 0 1 1
2 0 0 0 1 0 3
3 0 0 0 1 1 4
4 0 0 1 0 0 7
5 0 0 1 0 1 8
6 0 0 1 1 0 10
7 0 0 1 1 1 11
8 0 1 0 0 0 15
9 0 1 0 0 1 16
10 0 1 0 1 0 18
11 0 1 0 1 1 19
( n )
Thus, the average cost of each increment operation is Q(n)/n = Q(1).
3. Potential Method
IDEA: View the bank account as the potential energy (as in physics) of the dynamic
set.
FRAMEWORK:
Start with an initial data structure D0.
Operation i transforms Di–1 to Di.
The cost of operation i is ci.
Define a potential function F : {Di} R,
such that F(D0 ) = 0 and F(Di ) ³ 0 for all i.
The amortized cost ĉi with respect to F is defined to be ĉi = ci + F(Di) – F(Di–1).
Like the accounting method, but think of the credit as potential stored with the entire
data structure.
Accounting method stores credit with specific objects while potential method
stores potential in the data structure as a whole.
Can release potential to pay for future operations
Most flexible of the amortized analysis methods ).
ĉi = ci + F(Di) – F(Di–1)
If DFi > 0, then ĉi > ci. Operation i stores work in the data structure for later use.
If DFi < 0, then ĉi < ci. The data structure delivers up stored work to help pay for
operation i.
The total amortized cost of n operations is
n n
n
ci since F(Dn) ³ 0 and F(D0 ) = 0.
i 1
Stack Example
Define: (Di) = #items in stack Thus, (D0)=0.
Plug in for operations:
Push: ĉi = ci + (Di) - (Di-1)
=1+ j - (j-1)
=2
Pop: ĉi = ci + (Di) - (Di-1)
= 1 + (j-1) - j
=0
Multi-pop: ĉi = ci + (Di) - (Di-1)
= k’ + (j-k’) - j k’=min(|S|,k)
=0
ĉi = ci + F(Di) – F(Di–1)
= (ti + 1) + (1 ti)
=2
Therefore, n INCREMENTs cost Q(n) in the worst case
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 1
Unit - II
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Set:
A set is a collection of distinct elements. The Set can be
represented, for examples, as S1={1,2,5,10}.
Disjoint Sets:
The disjoints sets are those do not have any common element.
For example S1={1,7,8,9} and S2={2,5,10}, then we can say that
S1 and S2 are two disjoint sets.
Example:
S1={1,7,8,9} S2={2,5,10}
S1 U S2={1,2,5,7,8,9,10}
Find:
Given the element I, find the set containing i.
Example:
S1={1,7,8,9} S2={2,5,10} s3={3,4,6}
Then,
Find(4)= S3 Find(5)=S2 Find97)=S1
Set Representation:
The set will be represented as the tree structure where all
children will store the address of parent / root node. The root node
will store null at the place of parent address. In the given set of
elements any element can be selected as the root node, generally we
select the first node as the root node.
Example:
S1={1,7,8,9} S2={2,5,10} s3={3,4,6}
Then these sets can be represented as
Disjoint Union:
To perform disjoint set union between two sets Si and Sj can
take any one root and make it sub-tree of the other. Consider the
above example sets S1 and S2 then the union of S1 and S2 can be
represented as any one of the following.
Find:
To perform find operation, along with the tree structure we need to
mai
ntain
the name of each set. So, we require one more data structure to store
the set names. The data structure contains two fields. One is the set
name and the other one is the pointer to root.
Example:
For the following sets the array representation is as shown below.
i [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
p -1 -1 -1 3 2 3 1 1 1 2
Algorithm SimpleUnion(i,j)
{
P[i]:=j;
}
1 2 3 4 . . .n. . .
n-1
n-2
Since, the time taken for a Union is constant, the n-1 sequence of
union can be processed in time O(n). And for the sequence of Find
operations it will take time
n
complexity of O ( i ) = O(n ).
i1
2
Algorithm WeightedUnion(i,j)
//Union sets with roots i and j , i≠j using the weighted rule
// P[i]=-count[i] and p[j]=-count[j]
{
temp:= P[i]+P[j];
if (P[i]>P[j]) then
{// i as fewer nodes P[i]:=j;
P[j]:=temp;
}
else
{// j has fewer nodes P[j]:=i;
P[i]:=temp;
}
operations Find(8),
Find(8)………………………Find(8)
Algorithm CollapsingFind(i)
// Find the root of the tree containing element i
// use the collapsing rule to collapse all nodes from i to root.
{
r:=i;
while(P[r]>0) do
r:=P[r]; //Find root
while(i≠r)
{
//reset the parent node from element i
to the root s:=P[i];
P[i]:=r;
i:=s;
}
}
Search means finding a path or traversal between a start node and one of a set of
goal nodes. Search is a study of states and their transitions.
Search involves visiting nodes in a graph in a systematic manner, and may or may
not result into a visit to all nodes. When the search necessarily involved the
examination of every vertex in the tree, it is called the traversal.
Techniques for Traversal of a Binary Tree:
A binary tree is a finite (possibly empty) collection of elements. When the binary tree
is not empty, it has a root element and remaining elements (if any) are partitioned
into two binary trees, which are called the left and right subtrees.
1. Preorder
2. Inorder
3. postorder
In all the three traversal methods, the left subtree of a node is traversed before the
right subtree. The difference among the three orders comes from the difference in the
time at which a node is visited.
Inorder Traversal:
In the case of inorder traversal, the root of each subtree is visited after its left subtree
has been traversed but before the traversal of its right subtree begins. The steps for
traversing a binary tree in inorder traversal are:
treenode = record
{
Type data; //Type is the data type of data.
Treenode *lchild; treenode *rchild;
}
algorithm inorder (t)
// t is a binary tree. Each node of t has three fields: lchild, data, and rchild.
{
if t 0 then
{
inorder (t lchild);
visit (t);
inorder (t rchild);
}
}
Preorder Traversal:
In a preorder traversal, each node is visited before its left and right subtrees are
traversed. Preorder search is also called backtracking. The steps for traversing a
binary tree in preorder traversal are:
Postorder Traversal:
In a postorder traversal, each root is visited after its left and right subtrees have been
traversed. The steps for traversing a binary tree in postorder traversal are:
Example 1:
Inord eri ng of t he
vertices: D, B, A, E, G,
C, H, F, I
Bi n a ry T re e P re, P o st a n d In- o rd er T ra v ers in g
Example 2:
Traverse the following binary tree in pre, post, inorder and level order.
• Le v e l o rde r t ra v e rs a l y ie lds:
A, B, C , D, E, F , G , H, I
Bi n a ry T re e P re, P o st , In o rd er a n d l ev e l o rd er T ra v ers in g
Example 3:
Traverse the following binary tree in pre, post, inorder and level order.
• Le v e l o rde r t ra v e rs a l y ie lds:
P , F , S, B, H, R, Y, G , T, Z, W
Traverse the following binary tree in pre, post, inorder and level order.
• Le v e l o rde r t ra v e rs a l y ie lds:
2, 7 , 5 , 2 , 6 , 9 , 5 , 11 , 4
Bi n a ry T re e P re, P o st , In o rd er a n d l ev e l o rd er T ra v ers in g
Example 5:
Traverse the following binary tree in pre, post, inorder and level order.
At first glance, it appears we would always want to use the flat traversal functions
since the use less stack space. But the flat versions are not necessarily better. For
instance, some overhead is associated with the use of an explicit stack, which may
negate the savings we gain from storing only node pointers. Use of the implicit
function call stack may actually be faster due to special machine instructions that can
be used.
Inorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex, pushing each vertex onto
the stack and stop when there is no left son of vertex.
2. Pop and process the nodes on stack if zero is popped then exit. If a vertex with
right son exists, then set right son of vertex as current vertex and return to
step one.
The algorithm for inorder Non Recursive traversal is as follows:
Algorithm inorder()
{
stack[1] = 0
vertex = root
top: while(vertex ≠ 0)
{
push the vertex into the stack
vertex = leftson(vertex)
}
while(vertex ≠ 0)
{
print the vertex node
if(rightson(vertex) ≠ 0)
{
vertex = rightson(vertex)
goto top
}
pop the element from the stack and made it as vertex
}
}
Preorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path by pushing the right son of vertex onto stack,
if any and process each vertex. The traversing ends after a vertex with no left
child exists.
2. Pop the vertex from stack, if vertex ≠ 0 then return to step one otherwise exit.
Algorithm preorder( )
{
stack[1]: = 0
vertex := root.
while(vertex ≠ 0)
{
print vertex node
if(rightson(vertex) ≠ 0)
push the right son of vertex into the stack.
if(leftson(vertex) ≠ 0)
vertex := leftson(vertex)
else
pop the element from the stack and made it as vertex
}
}
Postorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex. At each vertex of path push
vertex on to stack and if vertex has a right son push –(right son of vertex)
onto stack.
2. Pop and process the positive nodes (left nodes). If zero is popped then exit. If
a negative node is popped, then ignore the sign and return to step one.
Algorithm postorder( )
{
stack[1] := 0
vertex := root
top: while(vertex ≠ 0)
{
push vertex onto stack
if(rightson(vertex) ≠ 0)
push -leftson(vertex) onto stack
vertex := leftson(vertex)
}
pop from stack and make it as vertex
while(vertex > 0)
{
print the vertex node
pop from stack and make it as vertex
}
if(vertex < 0)
{
vertex := -(vertex)
goto top
}
}
Example 1:
Traverse the following binary tree in pre, post and inorder using non-recursive
traversing algorithm.
Bi n a ry T re e P re, P o st a n d In o rd er T ra v ers in g
Inorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex, pushing each vertex onto
the stack and stop when there is no left son of vertex.
2. Pop and process the nodes on stack if zero is popped then exit. If a vertex with
right son exists, then set right son of vertex as current vertex and return to
step one.
Current
Stack Processed nodes Remarks
vertex
A 0 PUSH 0
K 0ABDG K POP K
E 0C KGDLHMBAE POP E
Postorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex. At each vertex of path push
vertex on to stack and if vertex has a right son push -(right son of vertex)
onto stack.
2. Pop and process the positive nodes (left nodes). If zero is popped then exit. If
a negative node is popped, then ignore the sign and return to step one.
Current
Stack Processed nodes Remarks
vertex
A 0 PUSH 0
PUSH the left most path of A with
0 A -C B D -H G K
a -ve for right sons
0 A -C B D -H KG POP all +ve nodes K and G
H 0 A -C B D KG Pop H
PUSH the left most path of H with
0 A -C B D H -M L KG
a -ve for right sons
0 A -C B D H -M KGL POP all +ve nodes L
M 0 A -C B D H KGL Pop M
PUSH the left most path of M with
0 A -C B D H M KGL
a -ve for right sons
0 A -C KGLMHDB POP all +ve nodes M, H, D and B
C 0A KGLMHDB Pop C
PUSH the left most path of C with
0ACE KGLMHDB
a -ve for right sons
0 KGLMHDBECA POP all +ve nodes E, C and A
Preorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path by pushing the right son of vertex onto stack,
if any and process each vertex. The traversing ends after a vertex with no left
child exists.
2. Pop the vertex from stack, if vertex ≠ 0 then return to step one otherwise exit.
Current
Stack Processed nodes Remarks
vertex
A 0 PUSH 0
PUSH the right son of each vertex onto
0CH ABDGK stack and process each vertex in the left
most path
H 0C ABDGK POP H
PUSH the right son of each vertex onto
0CM ABDGKHL stack and process each vertex in the left
most path
M 0C ABDGKHL POP M
PUSH the right son of each vertex onto
0C ABDGKHLM stack and process each vertex in the left
most path; M has no left path
C 0 ABDGKHLM Pop C
PUSH the right son of each vertex onto
stack and process each vertex in the left
0 ABDGKHLMCE
most path; C has no right son on the left
most path
0 ABDGKHLMCE Stop since stack is empty
Example 2:
Traverse the following binary tree in pre, post and inorder using non-recursive
traversing algorithm.
Bi n a ry T re e P re, P o st a n d In o rd er T ra v ers in g
Inorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex, pushing each vertex onto
the stack and stop when there is no left son of vertex.
2. Pop and process the nodes on stack if zero is popped then exit. If a vertex with
right son exists, then set right son of vertex as current vertex and return to
step one.
Current
Stack Processed nodes Remarks
vertex
2 0
0272
2 027 2
7 02 27
6 0265 27
5 026 275
11 02 2 7 5 6 11
5 05 2 7 5 6 11 2
9 094 2 7 5 6 11 2 5
4 09 2 7 5 6 11 2 5 4
0 2 7 5 6 11 2 5 4 9 Stop since stack is empty
Postorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path rooted at vertex. At each vertex of path push
vertex on to stack and if vertex has a right son push –(right son of vertex)
onto stack.
2. Pop and process the positive nodes (left nodes). If zero is popped then exit. If
a negative node is popped, then ignore the sign and return to step one.
Current
Stack Processed nodes Remarks
vertex
2 0
0 2 -5 7 -6 2
2 0 2 -5 7 -6 2
6 0 2 -5 7 2
0 2 -5 7 6 -11 5 2
5 0 2 -5 7 6 -11 25
11 0 2 -5 7 6 11 25
0 2 -5 2 5 11 6 7
5 0 2 5 -9 2 5 11 6 7
9 02594 2 5 11 6 7
0 2 5 11 6 7 4 9 5 2 Stop since stack is empty
Preorder Traversal:
Initially push zero onto stack and then set root as vertex. Then repeat the following
steps until the stack is empty:
1. Proceed down the left most path by pushing the right son of vertex onto stack,
if any and process each vertex. The traversing ends after a vertex with no left
child exists.
2. Pop the vertex from stack, if vertex ≠ 0 then return to step one otherwise exit.
Current
Stack Processed nodes Remarks
vertex
2 0
056 272
6 0 5 11 27265
11 05 27265
05 2 7 2 6 5 11
5 09 2 7 2 6 5 11
9 0 2 7 2 6 5 11 5
0 2 7 2 6 5 11 5 9 4 Stop since stack is empty
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 5
Unit - II
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Biconnecte
d
Component
s
Biconnected graphs and articulation points are of great interest in the design of
network algorithms, because these are the “critical" points, whose failure will result in
the network becoming disconnected.
Let us consider the typical case of vertex v, where v is not a leaf and v is not the root.
Let w1, w2, . . . . . . . wk be the children of v. For each child there is a subtree of the
DFS tree rooted at this child. If for some child, there is no back edge going to a
proper ancestor of v, then if we remove v, this subtree becomes disconnected from
the rest of the graph, and hence v is an articulation point.
On the other hand, if every one of the subtree rooted at the children of v have back
edges to proper ancestors of v, then if v is removed, the graph remains connected
(the back edges hold everything together). This leads to the following:
Observation 1: An internal vertex v of the DFS tree (other than the root) is
an articulation point if and only if there is a subtree rooted at a child of v such
that there is no back edge from any vertex in this subtree to a proper ancestor
of v.
Thus, after deletion of a leaf from a tree, the rest of the tree remains
connected, thus even ignoring the back edges, the graph is connected after
the deletion of a leaf from the DFS tree.
Observation 3: The root of the DFS is an articulation point if and only if it has
two or more children. If the root has only a single child, then (as in the case of
leaves) its removal does not disconnect the DFS tree, and hence cannot
disconnect the graph in general.
Determining the articulation turns out to be a simple extension of depth first search.
Consider a depth first spanning tree for this graph.
Deleting node E does not disconnect the graph because G and D both have dotted
links (back edges) that point above E, giving alternate paths from them to F. On the
other hand, deleting G does disconnect the graph because there are no such alternate
paths from L or H to E (G’s parent).
A vertex ‘x’ is not an articulation point if every child ‘y’ has some node lower in the
tree connect (via a dotted link) to a node higher in the tree than ‘x’, thus providing an
alternate connection from ‘x’ to ‘y’. This rule will not work for the root node since
there are no nodes higher in the tree. The root is an articulation point if it has two or
more children.
This observation leads to a simple rule to identify articulation points. For each is
define L (u) as follows:
L (u) = min {DFN (u), min {L (w) w is a child of u}, min {DFN (w) (u, w)
is a back edge}}.
L (u) is the lowest depth first number that can be reached from ‘u’ using a path of
descendents followed by at most one back edge. It follows that, If ‘u’ is not the root
then ‘u’ is an articulation point iff ‘u’ has a child ‘w’ such that:
6.7.1. Example:
For the following graph identify the articulation points and Biconnected components:
86
11
11 57
24
62
2 9
33
33 810
4 1 0 5 9 6 2
10 95
4
7 5
Grap h
86 79
810
L (u) = min {DFN (u), min {L (w) w is a child of u}, min {DFN (w) w is a vertex
to which there is back edge from u}}
L (1) = min {DFN (1), min {L (4)}} = min {1, L (4)} = min {1, 1} = 1
L (4) = min {DFN (4), min {L (3)}} = min {2, L (3)} = min {2, 1} = 1
Vertex 4: is not an articulation point as child 3 has L (3) = 1 and DFN (4) = 2,
So, the condition L (3) > DFN (4) is false.
Vertex 7: is not an articulation point as child 8 has L (8) = 6, and DFN (7) = 9,
So, the condition L (8) > DFN (7) is false.
Example:
For the following graph identify the articulation points and Biconnected components:
G ra p h
D F S s p a n ni n g T re e
V ert e x
1 2
2 1 3
3 2 5 6 4
4 3 7 8
5 3
6 3
7 4 8
8 4 7
Adj ac e nc y List
L (u) = min {DFN (u), min {L (w) w is a child of u}, min {DFN (w) w is a vertex
to which there is back edge from u}}
L (1) = min {DFN (1), min {L (2)}} = min {1, L (2)} = min {1, 2} = 1
L (2) = min {DFN (2), min {L (3)}} = min {2, L (3)} = min {2, 3} = 2
L (3) = min {DFN (3), min {L (4), L (5), L (6)}} = min {3, min {6, 4, 5}} = 3
L (4) = min {DFN (4), min {L (7)} = min {6, L (7)} = min {6, 6} = 6
L (5) = min {DFN (5)} = 4
L (6) = min {DFN (6)} = 5
L (7) = min {DFN (7), min {L (8)}} = min {7, 6} = 6
L (8) = min {DFN (8), min {DFN (4)}} = min {8, 6} = 6
Check for the condition if L (w) > DFN (u) is true, where w is any child of u.
Example:
For the following graph identify the articulation points and Biconnected components:
1 1
2 2
3 3
4 4
5 5 7 8
V ert e x
2 1 3
3 2 4 7
4 1 3 5 6 7 8
5 1 4 6
6 4 5 8
7 3 4
8 4 6
Adj ac e nc y List
L (u) = min {DFN (u), min {L (w) w is a child of u}, min {DFN (w) w is a vertex
to which there is back edge from u}}
L (2) = min {DFN (2), min {L (3)}} = min {2, L (3)} = min{2, 1}= 11
L (3) = min {DFN (3), min {L (4)}} = min {3, L (4)} = min {3, L (4)}
= min {3, 1} = 1
L (4) = min {DFN (4), min {L (5), L (7)}, min {DFN (1)}}
= min {4, min {L (5), L (7)}, 1} = min {4, min {1, 3}, 1}
= min {4, 1, 1} = 1
L (5) = min {DFN (5), min {L (6)}, min {DFN (1)}} = min {5, L (6), 1}
= min {5, 4, 1} = 1
L (6) = min {DFN (6), min {L (8)}, min {DFN (4)}} = min(6, L (8), 4}
= min(6, 4, 4} = 4
Check for the condition if L (w) > DFN (u) is true, where w is any child of u.
N, a set of nodes,
An ordinary graph is a special case of hypergraph in which all the sets of descendent
nodes have a cardinality of 1.
Hyperarcs also known as K-connectors, where K is the cardinality of the set of
decendent nodes. If K = 1, the descendent may be thought of as an OR nodes. If K >
1, the elements of the set of decendents may be thought of as AND nodes. In this
case the connector is drawn with individual edges from the parent node to each of the
decendent nodes; these individual edges are then joined with a curved link.
Example 1:
1. A
2. B
3. C
4. A ^ B -> D
5. A ^ C -> E
6. B ^ D -> F
7. F -> G
8. A ^ E -> H
C A B
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 1
Unit - III
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Divide and conquer strategy is as follows: divide the problem instance into
two or more smaller instances of the same problem, solve the smaller
instances recursively, and assemble the solutions to form a solution of the
original instance. The recursion stops when an instance is reached which is
too small to divide. When dividing the instance, one can either use whatever
division comes most easily to hand or invest time in making the division
carefully so that the assembly is simplified.
Divide : Divide the problem into a number of sub problems. The sub
problems are solved recursively.
Conquer : The solution to the original problem is then formed from the
solutions to the sub problems (patching together the
answers).
Traditionally, routines in which the text contains at least two recursive calls
are called divide and conquer algorithms, while routines whose text contains
only one recursive call are not. Divide–and–conquer is a very powerful use
of recursion.
DANDC (P)
{
if SMALL (P) then
return S (p); else
{
divide p into smaller instances p 1, p2, ….
Pk, k 1; apply DANDC to each of these
sub problems;
return (COMBINE (DANDC (p1) , DANDC (p2),…., DANDC (pk));
}
}
SMALL (P) is a Boolean valued function which determines whether the input
size is small enough so that the answer can be computed without splitting. If
this is so function ‘S’ is invoked otherwise, the problem ‘p’ into smaller sub
problems. These sub problems p1, p2, . . . , pk are solved by recursive
application of DANDC.
If the sizes of the two sub problems are approximately equal then the
computing time of DANDC is:
g (n) n small
T (n) =
2 T(n/2) f (n) otherwise
Binary Search
If we have ‘n’ records which have been ordered by keys so that x1 < x2 < … <
xn . When we are given a element ‘x’, binary search is used to find the
corresponding element from the list. In case ‘x’ is present, we have to
determine a value ‘j’ such that a[j] = x (successful search). If ‘x’ is not in the
list then j is to set to zero (un successful search).
In Binary search we jump into the middle of the file, where we find key a[mid],
and compare ‘x’ with a[mid]. If x = a[mid] then the desired record has been
found. If x < a[mid] then ‘x’ must be in that portion of the file that precedes
a[mid], if there at all. Similarly, if a[mid] > x, then further search is only
necessary in that past of the file which follows a[mid]. If we use recursive
procedure of finding the middle key a[mid] of the un-searched portion of a file,
then every un-successful comparison of ‘x’ with a[mid] will eliminate roughly
half the un-searched portion from consideration.
Since the array size is roughly halved often each comparison between ‘x’ and
a[mid], and since an array of length ‘n’ can be halved only about log2n times
before reaching a trivial length, the worst case complexity of Binary search is
about log2n
BINSRCH (a, n, x)
// array a(1 : n) of elements in increasing order, n 0,
// determine whether ‘x’ is present, and if so, set j such that x = a(j)
// else return j
{
low :=1 ; high
:=n ; while (low
< high) do
{
mid :=|(low + high)/2|
if (x < a [mid]) then high:=mid –
1; else if (x > a [mid]) then low:=
mid + 1
else return mid;
}
return 0;
}
low and high are integer variables such that each time through the loop either
‘x’ is found or low is increased by at least one or high is decreased by at least
one. Thus we have two sequences of integers approaching each other and
eventually low will become greater than high causing termination in a finite
number of steps if ‘x’ is not present.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 2
Unit - III
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
This strategy is so simple, and so efficient but the problem here is that there
seems to be no easy way to merge two adjacent sorted arrays together in place
(The result must be build up in a separate array).
The basic merging algorithm takes two input arrays ‘a’ and ’b’, an output array
‘c’, and three counters, a ptr, b ptr and c ptr, which are initially set to the
beginning of their respective arrays. The smaller of a[a ptr] and b[b ptr] is
copied to the next entry in ‘c’, and the appropriate counters are advanced.
When either input list is exhausted, the remainder of the other list is copied to
‘c’.
To illustrate how merge process works. For example, let us consider the array
‘a’ containing 1, 13, 24, 26 and ‘b’ containing 2, 15, 27, 38. First a comparison
is done between 1 and 2. 1 is copied to ‘c’. Increment a ptr and c ptr.
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1
h j i
ptr ptr ptr
and then 2 and 13 are compared. 2 is added to ‘c’. Increment b ptr and c ptr.
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2
h j i
ptr ptr ptr
then 13 and 15 are compared. 13 is added to ‘c’. Increment a ptr and c ptr.
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2 13
h j i
ptr ptr ptr
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2 13 15
h j i
ptr ptr ptr
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2 13 15 24
h j i
ptr ptr ptr
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2 13 15 24 26
h j i
ptr ptr ptr
As one of the lists is exhausted. The remainder of the b array is then copied to ‘c’.
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
1 13 24 26 2 15 27 28 1 2 13 15 24 26 27 28
h j i
ptr ptr ptr
Algorithm
Example
7, 2, 9, 4 | 3, 8, 6, 1 1, 2, 3, 4, 6, 7, 8, 9
Tree Calls of MERGESORT(1, 8)
The following figure represents the sequence of recursive calls that are produced by
MERGESORT when it is applied to 8 elements. The values in each node are the values
of the parameters low and high.
1, 8
1, 4 5, 8
1, 2 3, 4 5, 6 7, 8
1, 1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 8, 8
1, 1, 2 3, 3, 4 5, 5, 6 7, 7, 8
1, 2, 4 5, 6, 8
1, 4, 8
We will assume that ‘n’ is a power of 2, so that we always split into even halves, so
we solve for the case n = 2k.
T(1) = 1
T(n) = 2 T(n/2) + n
This is a standard recurrence relation, which can be solved several ways. We will
solve by substituting recurrence relation continually on the right–hand side.
T(n/2) = 2 T(n/4) + n
T(n) = 4 T(n/4) + 2n
T(n/4) = 2 T(n/8) + n
T(n) = 8 T(n/8) + 3n
T(n) = 2k T(n/2k) + K. n
Quick Sort
The main reason for the slowness of Algorithms like SIS is that all comparisons
and exchanges between keys in a sequence w 1, w2, . . . . , wn take place between
adjacent pairs. In this way it takes a relatively long time for a key that is badly out
of place to work its way into its proper position in the sorted sequence.
Hoare his devised a very efficient way of implementing this idea in the early
1960’s that improves the O(n2) behavior of SIS algorithm with an expected
performance that is O(n log n).
In essence, the quick sort algorithm partitions the original array by rearranging it
into two groups. The first group contains those elements less than some arbitrary
chosen value taken from the set, and the second group contains those elements
greater than or equal to the chosen value.
The chosen value is known as the pivot element. Once the array has been
rearranged in this way with respect to the pivot, the very same partitioning is
recursively applied to each of the two subsets. When all the subsets have been
partitioned and rearranged, the original array is sorted.
The function partition() makes use of two pointers ‘i’ and ‘j’ which are moved
toward each other in the following fashion:
Repeat the steps 1, 2 and 3 till the ‘i’ pointer crosses the ‘j’ pointer. If ‘i’
pointer crosses ‘j’ pointer, the position for pivot is found and place pivot
element in ‘j’ pointer position.
It terminates when the condition low >= high is satisfied. This condition
will be satisfied only when the array is completely sorted.
Here we choose the first element as the ‘pivot’. So, pivot = x[low]. Now
it calls the partition function to find the proper position j of the element
x[low] i.e. pivot. Then we will have two sub-arrays x[low], x[low+1], . .
..
. . . x[j-1] and x[j+1], x[j+2], . . .x[high].
Algorithm
Algorithm
QUICKSORT(low,
high)
/* sorts the elements a(low), . . . . . , a(high) which reside in the global array A(1 :
n) into ascending order a (n + 1) is considered to be defined and must be
greater than all elements in a(1 : n); A(n + 1) = + */
{
if low < high then
{
j := PARTITION(a, low, high+1);
// J is the position of the partitioning element
QUICKSORT(low, j – 1);
QUICKSORT(j + 1 , high);
}
}
Algorithm PARTITION(a, m, p)
{
V a(m); i m; j p; // A (m) is the partition
element do
{
loop i := i + 1 until a(i) > v // i moves left to
right loop j := j – 1 until a(j) < v // p moves right to
left if (i < j) then INTERCHANGE(a, i, j)
} while (i > j);
a[m] :=a[j]; a[j] :=V; // the partition element belongs at position P
return j;
}
Algorithm INTERCHANGE(a, i, j)
{
P:=a[i];
a[i] :=
a[j]; a[j]
:= p;
}
Like merge sort, quick sort is recursive, and hence its analysis requires solving a
recurrence formula. We will do the analysis for a quick sort, assuming a random
pivot (and no cut off for small files).
We will take T (0) = T (1) = 1, as in merge sort.
The running time of quick sort is equal to the running time of the two recursive
calls plus the linear time spent in the partition (The pivot selection takes only
constant time). This gives the basic quick sort relation:
The pivot is the smallest element, all the time. Then i=0 and if we ignore T(0)=1,
which is insignificant, the recurrence is:
T (n – 1) = T (n – 2) + C (n – 1)
T (n – 2) = T (n – 3) + C (n – 2)
------- -
n
T (n) T (1)
i 2
i
= O (n2) - (3)
In the best case, the pivot is in the middle. To simply the math, we assume that the
two sub-files are each exactly half the size of the original and although this gives a
slight over estimate, this is acceptable because we are only interested in a Big – oh
answer.
T(n) T(n / 2)
C - (5)
n n /2
T(n / 2) T(n / 4)
C - (6)
n/2 n/4
Substitute n/4 for ‘n’ in equation (6)
T(n / 4) T(n / 8)
C - (7)
n/4 n/8
--------
--------
Continuing in this manner, we obtain:
T(2) T(1)
C - (8)
2 1
We add all the equations from 4 to 8 and note that there are log n of them:
T(n) T(1)
C log n - (9)
n 1
Which yields, T (n) = C n log n + n = O(n log n) - (10)
This is exactly the same analysis as merge sort, hence we get the same
answer.
The number of comparisons for first call on partition: Assume left_to_right moves
over k smaller element and thus k comparisons. So when right_to_left crosses
left_to_right it has made n-k+1 comparisons. So, first call on partition makes
n+1 comparisons. The average case complexity of quicksort is
Greedy is the most straight forward design technique. Most of the problems have n
inputs and require us to obtain a subset that satisfies some constraints. Any subset
that satisfies these constraints is called a feasible solution. We need to find a feasible
solution that either maximizes or minimizes the objective function. A feasible solution
that does this is called an optimal solution.
For the problems that make decisions by considering the inputs in some order, each
decision is made using an optimization criterion that can be computed using decisions
already made. This version of greedy method is ordering paradigm. Some problems like
optimal storage on tapes, optimal merge patterns and single source shortest path are
based on ordering paradigm.
CONTROL ABSTRACTION
Procedure Greedy describes the essential way that a greedy based algorithm will look,
once a particular problem is chosen and the functions select, feasible and union are
properly implemented.
The function select selects an input from ‘a’, removes it and assigns its value to ‘x’.
Feasible is a Boolean valued function, which determines if ‘x’ can be included into the
solution vector. The function Union combines ‘x’ with solution and updates the objective
function.
KNAPSACK PROBLEM
Let us apply the greedy method to solve the knapsack problem. We are given ‘n’
objects and a knapsack. The object ‘i’ has a weight wi and the knapsack has a capacity
‘m’. If a fraction xi, 0 < xi < 1 of object i is placed into the knapsack then a profit of p i
xi is earned. The objective is to fill the knapsack that maximizes the total profit earned.
Since the knapsack capacity is ‘m’, we require the total weight of all chosen objects to
be at most ‘m’. The problem is stated as:
n
maximize p x i i
i 1
n
Algorithm
If the objects are already been sorted into non-increasing order of p[i] / w[i] then the
algorithm given below obtains solutions corresponding to this strategy.
Running time:
Example:
Consider the following instance of the knapsack problem: n = 3, m = 20, (p 1, p2, p3) =
(25, 24, 15) and (w1, w2, w3) = (18, 15, 10).
1. First, we try to fill the knapsack by selecting the objects in some order:
x1 x2 x3 wi xi pi xi
1/2 1/3 1/4 18 x 1/2 + 15 x 1/3 + 10 x 1/4 25 x 1/2 + 24 x 1/3 + 15 x 1/4 =
= 16.5 24.25
2. Select the object with the maximum profit first (p = 25). So, x1 = 1 and profit
earned is 25. Now, only 2 units of space is left, select the object with next
largest profit (p = 24). So, x2 = 2/15
x1 x2 x3 wi xi pi xi
1 2/15 0 18 x 1 + 15 x 2/15 = 20 25 x 1 + 24 x 2/15 = 28.2
x1 x2 x3 wi xi pi xi
0 2/3 1 15 x 2/3 + 10 x 1 = 20 24 x 2/3 + 15 x 1 = 31
Sort the objects in order of the non-increasing order of the ratio pi / xi. Select the
object with the maximum pi / xi ratio, so, x2 = 1 and profit earned is 24. Now,
only 5 units of space is left, select the object with next largest pi / xi ratio, so x3 =
½ and the profit earned is 7.5.
x1 x2 x3 wi xi pi xi
0 1 1/2 15 x 1 + 10 x 1/2 = 20 24 x 1 + 15 x 1/2 = 31.5
There are ‘n’ programs that are to be stored on a computer tape of length ‘L’. Each
program ‘i’ is of length li, 1 ≤ i ≤ n. All the programs can be stored on the tape if
and only if the sum of the lengths of the programs is at most ‘L’.
We shall assume that whenever a program is to be retrieved from this tape, the
tape is initially positioned at the front. If the programs are stored in the order i = i 1,
i2, . . . . .
, in, the time tJ needed to retrieve program iJ is proportional to
l
1 k j
ik
If all the programs are retrieved equally often then the expected or mean retrieval time
(MRT) is:
1
.
t
j
n 1 J n
For the optimal storage on tape problem, we are required to find the permutation for
the ‘n’ programs so that when they are stored on the tape in this order the MRT is
minimized.
n J
d (I) l i k
J 1 K 1
Example
Let n = 3, (l1, l2, l3) = (5, 10, 3). Then find the optimal ordering?
Solution:
Ordering I d(I)
1, 2, 3 5 + (5 +10) +(5 + 10 + 3) = 38
1, 3, 2 5 + (5 + 3) + (5 + 3 + 10) = 31
2, 1, 3 10 + (10 + 5) + (10 + 5 + 3) = 43
2, 3, 1 10 + (10 + 3) + (10 + 3 + 5) = 41
3, 1, 2 3 + (3 + 5) + (3 + 5 + 10) = 29
3, 2, 1 3 + (3 + 10) + (3 + 10 + 5) = 34
From the above, it simply requires to store the programs in non-decreasing order
(increasing order) of their lengths. This can be carried out by using a efficient sorting
algorithm (Heap sort). This ordering can be carried out in O (n log n) time using heap
sort algorithm.
The tape storage problem can be extended to several tapes. If there are m 1 tapes,
To, . . . . . . ,Tm – 1, then the programs
m1
are to be distributed over these tapes.
The programs are to be sorted in non decreasing order of their lengths l i’s, l1 < l2 < .. .
.. . . ln.
The first ‘m’ programs will be assigned to tapes To, . . . . ,Tm-1 respectively. The next ‘m’
programs will be assigned to T0, . . . . ,Tm-1 respectively. The general rule is that
program i is stored on tape Ti mod m.
Algorithm:
On any given tape, the programs are stored in non-decreasing order of their lengths.
When we are given a set of ‘n’ jobs. Associated with each Job i, deadline d i > 0 and
profit Pi > 0. For any job ‘i’ the profit pi is earned iff the job is completed by its
deadline. Only one machine is available for processing jobs. An optimal solution is
the feasible solution with maximum profit.
Sort the jobs in ‘j’ ordered by their deadlines. The array d [1 : n] is used to store the
deadlines of the order of their p-values. The set of jobs j [1 : k] such that j [r], 1 ≤ r
≤ k are the jobs in ‘j’ and d (j [1]) ≤ d (j[2]) ≤ . . . ≤ d (j[k]). To test whether J U
{i} is feasible, we have just to insert i into J preserving the deadline ordering and
then verify that d [J[r]] ≤ r, 1 ≤ r ≤ k+1.
Example:
Let n = 4, (P1, P2, P3, P4,) = (100, 10, 15, 27) and (d1 d2 d3 d4) = (2, 1, 2, 1). The
feasible solutions and their values are:
Algorithm:
Basic Definitions:
Graph G is a pair (V, E), where V is a finite set (set of vertices) and E is a
finite set of pairs from V (set of edges). We will often denote n := |V|, m :=
|E|.
Representation of Graphs:
1, if (v , v ) E,
a i, j i j
0, otherwise
We may consider various modifications. For example for weighted graphs, we may
have
w (vi, v j ), if (vi , v j ) E,
a i, j
default, otherwise,
Where default is some sensible value based on the meaning of the weight function
(for example, if weight function represents length, then default can be , meaning
value larger than any other value).
Adjacency List: An array Adj [1 . . . . . . . n] of pointers where for 1 < v < n, Adj [v]
points to a linked list containing the vertices which are adjacent to v (i.e. the vertices
that can be reached from v by a single edge). If the edges have weights then these
weights may also be stored in the linked list elements.
A path is a sequence of vertices (v1, v2, . . . . . . , vk), where for all i, (vi, vi+1) E. A
path is simple if all vertices in the path are distinct.
A (simple) cycle is a sequence of vertices (v1, v2, . . . . . . , vk, vk+1 = v1), where for
all i, (vi, vi+1) E and all vertices in the cycle are distinct except pair v 1, vk+1.
The undirected graph G is connected, if for every pair of vertices u, v there exists a
path from u to v. If a graph is not connected, the vertices of the graph can be divided
into connected components. Two vertices are in the same connected component iff
they are connected by a path.
A spanning tree for a connected graph is a tree whose vertex set is the same as the
vertex set of the given graph, and whose edge set is a subset of the edge set of the
given graph. i.e., any connected graph will have a spanning tree.
Weight of a spanning tree w (T) is the sum of weights of all edges in T. The Minimum
spanning tree (MST) is a spanning tree with the smallest possible weight.
G:
A gra p h G:
T h re e ( of ma n y p o s s ib l e) s p a n n in g t re e s f ro m gra p h G:
2 2
4
G: 3 5 3
6
1 1
To explain further upon the Minimum Spanning Tree, and what it applies to, let's
consider a couple of real-world examples:
2. Another useful application of MST would be finding airline routes. The vertices of
the graph would represent cities, and the edges would represent routes between
the cities. Obviously, the further one has to travel, the more it will cost, so MST
can be applied to optimize airline routes by finding the least costly paths with no
cycles.
To explain how to find a Minimum Spanning Tree, we will look at two algorithms: the
Kruskal algorithm and the Prim algorithm. Both algorithms differ in their methodology,
but both eventually end up with the MST. Kruskal's algorithm uses edges, and Prim’s
algorithm uses vertex connections in determining the MST.
Kruskal’s Algorithm
This is a greedy algorithm. A greedy algorithm chooses some local optimum (i.e.
picking an edge with the least weight in a MST).
Kruskal's algorithm works as follows: Take a graph with 'n' vertices, keep on adding the
shortest (least cost) edge, while avoiding the creation of cycles, until (n - 1) edges
have been added. Sometimes two or more edges may have the same cost. The order in
which the edges are chosen, in this case, does not matter. Different MSTs may result,
but they will all have the same total cost, which will always be the minimum cost.
Algorithm:
The algorithm for finding the MST, using the Kruskal’s method is as follows:
Running time:
The number of finds is at most 2e, and the number of unions at most n-1.
Including the initialization time for the trees, this part of the algorithm has a
complexity that is just slightly more than O (n + e).
We can add at most n-1 edges to tree T. So, the total time for operations on T is
O(n).
Example 1:
10 50
1 2
45 40
30 35
25
55
20 15
Arrange all the edges in the increasing order of their costs:
Cost 10 15 20 25 30 35 40 45 50 55
Edge (1, 2) (3, 6) (4, 6) (2, 6) (1, 4) (3, 5) (2, 5) (1, 5) (2, 3) (5, 6)
The edge set T together with the vertices of G define a graph that has up to n
connected components. Let us represent each component by a set of vertices in it.
These vertex sets are disjoint. To determine whether the edge (u, v) creates a cycle,
we need to check whether u and v are in the same vertex set. If so, then a cycle is
created. If not then no cycle is created. Hence two Finds on the vertex sets suffice.
When an edge is included in T, two components are combined into one and a union is
to be performed on the two sets.
A given graph can have many spanning trees. From these many spanning trees, we
have to select a cheapest one. This tree is called as minimal cost spanning tree.
Minimal cost spanning tree is a connected undirected graph G in which each edge is
labeled with a number (edge labels may signify lengths, weights other than costs).
Minimal cost spanning tree is a spanning tree for which the sum of the edge labels
is as small as possible
The slight modification of the spanning tree algorithm yields a very simple algorithm
for finding an MST. In the spanning tree algorithm, any vertex not in the tree but
connected to it by an edge can be added. To find a Minimal cost spanning tree, we
must be selective - we must always add a new vertex for which the cost of the new
edge is as small as possible.
This simple modified algorithm of spanning tree is called prim's algorithm for finding
an Minimal cost spanning tree.
Prim's algorithm is an example of a greedy algorithm.
For each vertex u in the graph we dequeue it and check all its neighbors in (1 + deg
(u)) time. Therefore the running time is:
n
1degv degv (n
m)
v V v V
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 7
Unit - III
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
In the previously studied graphs, the edge labels are called as costs, but here we think
them as lengths. In a labeled graph, the length of the path is defined to be the sum of
the lengths of its edges.
In the single source, all destinations, shortest path problem, we must find a shortest
path from a given source vertex to each of the vertices (called destinations) in the
graph to which there is a path.
Dijkstra’s algorithm is similar to prim's algorithm for finding minimal spanning trees.
Dijkstra’s algorithm takes a labeled graph and a pair of vertices P and Q, and finds the
shortest path between then (or one of the shortest paths) if there is more than one.
The principle of optimality is the basis for Dijkstra’s algorithms.
The figure lists the shortest paths from vertex 1 for a five vertex weighted digraph.
8 0
4 2
2
4
Graph
6
Shortest Paths
Algorithm:
Running time:
Dynamic programming differs from the greedy method since the greedy method
produces only one feasible solution, which may or may not be optimal, while dynamic
programming produces all possible sub-problems at most once, one of which
guaranteed to be optimal. Optimal solutions to sub-problems are retained in a table,
thereby avoiding the work of recomputing the answer every time a sub-problem is
encountered
The divide and conquer principle solve a large problem, by breaking it up into smaller
problems which can be solved independently. In dynamic programming this principle
is carried to an extreme: when we don't know exactly which smaller problems to
solve, we simply solve them all, then store the answers away in a table to be used
later in solving larger problems. Care is to be taken to avoid recomputing previously
computed values, otherwise the recursive program will have prohibitive complexity.
In some cases, the solution can be improved and in other cases, the dynamic
programming technique is the best approach.
Two difficulties may arise in any application of dynamic programming:
Let the vertex ‘s’ is the source, and ‘t’ the sink. Let c (i, j) be the cost of edge <i, j>.
The cost of a path from ‘s’ to ‘t’ is the sum of the costs of the edges on the path. The
multistage graph problem is to find a minimum cost path from ‘s’ to ‘t’. Each set Vi
defines a stage in the graph. Because of the constraints on E, every path from ‘s’ to
‘t’ starts in stage 1, goes to stage 2, then to stage 3, then to stage 4, and so on, and
eventually terminates in stage k.
ALGORITHM:
The multistage graph problem can also be solved using the backward approach.
Let bp(i, j) be a minimum cost path from vertex s to j vertex in V i. Let Bcost(i, j) be
the cost of bp(i, j). From the backward approach we obtain:
Complexity Analysis:
The complexity analysis of the algorithm is fairly straightforward. Here, if G has E
edges, then the time for the first for loop is (V +E).
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 2
Unit - IV
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
When no edge has a negative length, the all-pairs shortest path problem may be
solved by using Dijkstra’s greedy single source algorithm n times, once with each of
the n vertices as the source vertex.
The all pairs shortest path problem is to determine a matrix A such that A (i, j) is the
length of a shortest path from i to j. The matrix A can be obtained by solving n
single-source problems using the algorithm shortest Paths. Since each application of
this procedure requires O (n2) time, the matrix A can be obtained in O (n3) time.
The dynamic programming solution, called Floyd’s algorithm, runs in O (n3) time.
Floyd’s algorithm works even when the graph has negative length edges (provided
there are no negative length cycles).
Ak (i, j) = {min {min {Ak-1 (i, k) + Ak-1 (k, j)}, c (i, j)}
1<k<n
Given a weighted digraph G = (V, E) with weight. Determine the length of the
shortest path between all pairs of vertices in G. Here we assume that there are no
cycles with zero or negative cost.
6
1 2 0 4 11
4
0
Cost adjacency matrix (A ) = 6 0 2
3 1 1 2
3 0
3
General formula: min {Ak-1 (i, k) + Ak-1 (k, j)}, c (i, j)}
1<k<n
0 4 11
(1)
A = 2
6 0
3 7 0
A2 (1, 1) = min {(A1 (1, 2) + A1 (2, 1), c (1, 1)} = min {(4 + 6), 0} = 0
A2 (1, 2) = min {(A1 (1, 2) + A1 (2, 2), c (1, 2)} = min {(4 + 0), 4} = 4
A2 (1, 3) = min {(A1 (1, 2) + A1 (2, 3), c (1, 3)} = min {(4 + 2), 11} = 6
A2 (2, 1) = min {(A (2, 2) + A (2, 1), c (2, 1)} = min {(0 + 6), 6} = 6
A2 (2, 2) = min {(A (2, 2) + A (2, 2), c (2, 2)} = min {(0 + 0), 0} = 0
A2 (2, 3) = min {(A (2, 2) + A (2, 3), c (2, 3)} = min {(0 + 2), 2} = 2
A2 (3, 1) = min {(A (3, 2) + A (2, 1), c (3, 1)} = min {(7 + 6), 3} = 3
A2 (3, 2) = min {(A (3, 2) + A (2, 2), c (3, 2)} = min {(7 + 0), 7} = 7
A2 (3, 3) = min {(A (3, 2) + A (2, 3), c (3, 3)} = min {(7 + 2), 0} = 0
0 4 6
(2)
A = 2
6 0
3 7 0
A3 (1, 1) = min {A2 (1, 3) + A2 (3, 1), c (1, 1)} = min {(6 + 3), 0} = 0
A3 (1, 2) = min {A2 (1, 3) + A2 (3, 2), c (1, 2)} = min {(6 + 7), 4} = 4
A3 (1, 3) = min {A2 (1, 3) + A2 (3, 3), c (1, 3)} = min {(6 + 0), 6} = 6
A3 (2, 1) = min {A2 (2, 3) + A2 (3, 1), c (2, 1)} = min {(2 + 3), 6} = 5
A3 (2, 2) = min {A2 (2, 3) + A2 (3, 2), c (2, 2)} = min {(2 + 7), 0} = 0
A3 (2, 3) = min {A2 (2, 3) + A2 (3, 3), c (2, 3)} = min {(2 + 0), 2} = 2
A3 (3, 1) = min {A2 (3, 3) + A2 (3, 1), c (3, 1)} = min {(0 + 3), 3} = 3
A3 (3, 2) = min {A2 (3, 3) + A2 (3, 2), c (3, 2)} = min {(0 + 7), 7} = 7
A3 (3, 3) = min {A2 (3, 3) + A2 (3, 3), c (3, 3)} = min {(0 + 0), 0} = 0
0 4 6
A(3) = 5 2
0
3 7 0
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 3
Unit - IV
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Let G = (V, E) be a directed graph with edge costs Cij. The variable cij is defined such
that cij > 0 for all I and j and cij = if < i, j> E. Let |V| = n and assume n > 1. A
tour of G is a directed simple cycle that includes every vertex in V. The cost of a tour
is the sum of the cost of the edges on the tour. The traveling sales person problem is
to find a tour of minimum cost. The tour is to be a simple path that starts and ends
at vertex 1.
Let g (i, S) be the length of shortest path starting at vertex i, going through all
vertices in S, and terminating at vertex 1. The function g (1, V – {1}) is the length of
an optimal salesperson tour. From the principal of optimality it follows that:
The Equation can be solved for g (1, V – 1}) if we know g (k, V – {1, k}) for all
choices of k.
Example 1:
For the following graph find minimum cost tour for the traveling salesperson
problem:
0 10 15 20
5
The cost adjacency matrix = 0 9 10
6 13 0 12
8 9 0
8
Let us start the tour from vertex 1:
g (2, ) = C21 = 5
g (3, ) = C31 = 6
g (4, ) = C41 = 8
g (1, {2, 3, 4}) = min {c12 + g (2, {3, 4}, c13 + g (3, {2, 4}), c14 + g (4, {2, 3})}
g (2, {3, 4}) = min {c23 + g (3, {4}), c24 + g (4, {3})}
= min {9 + g (3, {4}), 10 + g (4, {3})}
g (3, {2, 4}) = min {(c32 + g (2, {4}), (c34 + g (4, {2})}
Therefore, g (3, {2, 4}) = min {13 + 18, 12 + 13} = min {41, 25} = 25
g (4, {2, 3}) = min {c42 + g (2, {3}), c43 + g (3, {2})}
Therefore, g (4, {2, 3}) = min {8 + 15, 9 + 18} = min {23, 27} = 23
g (1, {2, 3, 4}) = min {c12 + g (2, {3, 4}), c13 + g (3, {2, 4}), c14 + g (4, {2, 3})}
= min {10 + 25, 15 + 25, 20 + 23} = min {35, 40, 43} = 35
Let us assume that the given set of identifiers is {a1, . . . , an} with a1 < a2 < . . . . <
an. Let p (i) be the probability with which we search for ai. Let q (i) be the probability
that the identifier x being searched for is such that ai < x < ai+1, 0 < i < n (assume
a0 = - and an+1 = +). We have to arrange the identifiers in a binary search tree in
a way that minimizes the expected total access time.
In a binary search tree, the number of comparisons needed to access an element at
depth 'd' nis d + 1, so if 'ai' is placed at depth 'di', then we want to minimize:
Pi (1 di ) .
i 1
Let P (i) be the probability with which we shall be searching for 'a i'. Let Q (i) be the
probability of an un-successful search. Every internal node represents a point where
a successful search may terminate. Every external node represents a point where an
unsuccessful search may terminate.
The expected cost contribution for the internal node for 'ai' is:
Unsuccessful search terminate with I = 0 (i.e at an external node). Hence the cost
contribution for this node is:
The computation of each of these c(i, j)’s requires us to find the minimum of m
quantities. Hence, each such c(i, j) can be computed in time O(m). The total time for
all c(i, j)’s with j – i = m is therefore O(nm – m2).
The total time to evaluate all the c(i, j)’s and r(i, j)’s is therefore:
nm m O n
st o p
2 3
1 m n
Example 1:
Let n = 4, and (a1, a2, a3, a4) = (do, if, need, while) Let P (1: 4) = (3, 3, 1, 1) and Q
(0: 4) = (2, 3, 1, 1, 1)
Solution:
Column
0 1 2 3 4
Row
0 2, 0, 0 3, 0, 0 1, 0, 0 1, 0, 0, 1, 0, 0
1 8, 8, 1 7, 7, 2 3, 3, 3 3, 3, 4
4 16, 32, 2
This computation is carried out row-wise from row 0 to row 4. Initially, W (i, i) = Q
(i) and C (i, i) = 0 and R (i, i) = 0, 0 < i < 4.
From the table we see that C (0, 4) = 32 is the minimum cost of a binary search tree
for (a1, a2, a3, a4). The root of the tree 'T04' is 'a2'.
Hence the left sub tree is 'T01' and right sub tree is T24. The root of 'T01' is 'a1' and the
root of 'T24' is a3.
The left and right sub trees for 'T01' are 'T00' and 'T11' respectively. The root of T01 is
'a1'
The left and right sub trees for T24 are T22 and T34 respectively.
a1 a3
T 01 T 24 do re a d
a4
T 00 T 11 T 22 T 34 wh ile
Example 2:
Column
0 1 2 3 4
Row
0 2, 0, 0 1, 0, 0 1, 0, 0 1, 0, 0, 1, 0, 0
1 9, 9, 1 6, 6, 2 3, 3, 3 3, 3, 4
4 16, 33, 2
From the table we see that C (0, 4) = 33 is the minimum cost of a binary search tree
for (a1, a2, a3, a4)
Hence the left sub tree is 'T01' and right sub tree is T24. The root of 'T01' is 'a1' and the
root of 'T24' is a3.
The left and right sub trees for 'T01' are 'T00' and 'T11' respectively. The root of T01 is
'a1'
The left and right sub trees for T24 are T22 and T34 respectively.
a1 a3
T 01 T 24 a1 a3
a4
T 00 T 11 T 22 T 34 a4
Example 3:
WORD PROBABILITY
A 4
B 2
C 1
D 3
E 5
F 2
G 1
and all other elements have zero probability.
Solving c(0,n):
0/1 – KNAPSACK-CO4
We are given n objects and a knapsack. Each object i has a positive weight w i and a
positive value Vi. The knapsack can carry a weight not exceeding W. Fill the knapsack
so that the value of objects in the knapsack is optimized.
Equation-2 can be solved for fn (m) by beginning with the knowledge fo (y) = 0 for all
y and fi (y) = - , y < 0. Then f1, f2, . . . fn can be successively computed using
equation–2.
When the wi’s are integer, we need to compute fi (y) for integer y, 0 < y < m. Since fi
(y) = - for y < 0, these function values need not be computed explicitly. Since
each fi can be computed from fi - 1 in Θ (m) time, it takes Θ (m n) time to compute
fn. When the wi’s are real numbers, fi (y) is needed for real numbers y such that 0 <
y < m. So, fi cannot be explicitly computed for all y in this range. Even when the w i’s
are integer, the explicit Θ (m n) computation of fn may not be the most efficient
computation. So, we explore an alternative method for both cases.
The fi (y) is an ascending step function; i.e., there are a finite number of y’s, 0 = y1
< y2 < . . . . < yk, such that fi (y1) < fi (y2) < . . . . . < fi (yk); fi (y) = - , y < y1; fi
(y) = f (yk), y > yk; and fi (y) = fi (yj), yj < y < yj+1. So, we need to compute only fi
(yj), 1 < j < k. We use the ordered set Si = {(f (yj), yj) | 1 < j < k} to represent fi
(y). Each number of Si is a pair (P, W), where P = fi (yj) and W = yj. Notice that S0 =
{(0, 0)}. We can compute Si+1 from Si by first computing:
Example 1:
Consider the knapsack instance n = 3, (w1, w2, w3) = (2, 3, 4), (P1, P2, P3) = (1, 2,
5) and M = 6.
Solution:
Other Solution:
X - 2 = 0 => x = 2. y – 3 = 0 => y = 3
X - 2 = 1 => x = 3. y – 3 = 2 => y = 5
S3 = (S2 U S21) = {(0, 0), (1, 2), (2, 3), (3, 5), (5, 4), (6, 6), (7, 7), (8, 9)}
S3 = (S2 U S21) = {(0, 0), (1, 2), (2, 3), (5, 4), (6, 6)}
From (6, 6) we can infer that the maximum Profit pi xi = 6 and weight xi wi = 6
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 5
Unit - IV
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Our problem is to use device duplication. This maximization is to be carried out under
a cost constraint. Let ci be the cost of each unit of device i and let c be the maximum
allowable cost of the system being designed.
We wish to solve:
Maximize
1 i n
i mi
Subject to C m C
1 i n
i i
Example 1:
Design a three stage system with device types D1, D2 and D3. The costs are $30, $15
and $20 respectively. The Cost of the system is to be no more than $105. The
reliability of each device is 0.9, 0.8 and 0.5 respectively.
Solution:
We assume that if if stage I has mi devices of type i in parallel, then i (mi) =1 – (1-
ri)mi
Since, we can assume each ci > 0, each mi must be in the range 1 ≤ mi ≤ ui. Where:
n
u i C Ci
CJ
Ci
1
S1 = depends on u1 value, as u1 = 2, so
S1 S , S
1 1
1 2
S2 = depends on u2 value, as u2 = 3, so
S2 S 2
, S 2 , S2
1 2 3
S3 = depends on u3 value, as u3 = 3, so
S3 S , S 3 3
, S3
1 2 3
Now find,S1
1
f (x), x
1
Next findS
2
f (x), x
1 2
Dominance Rule:
If Si contains two pairs (f1, x1) and (f2, x2) with the property that f1 ≥ f2 and x1 ≤ x2,
then (f1, x1) dominates (f2, x2), hence by dominance rule (f2, x2) can be discarded.
Discarding or pruning rules such as the one above is known as dominance rule.
Dominating tuples will be present in Si and Dominated tuples has to be discarded
from Si.
The best design has a reliability of 0.648 and a cost of 100. Tracing back for the solution
through Si ‘s we can determine that m3 = 2, m2 = 2 and m1 = 1.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 6
Unit - IV
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
BACKTRACKING -CO4
General Method:
The solution is based on finding one or more vectors that maximize, minimize, or
satisfy a criterion function P (x1, . . . . . , xn). Form a solution and check at every step
if this has any chance of success. If the solution at any point seems not promising,
ignore it. All solutions requires a set of constraints divided into two categories: explicit
and implicit constraints.
Definition 1: Explicit constraints are rules that restrict each x i to take on values only
from a given set. Explicit constraints depend on the particular instance I
of problem being solved. All tuples that satisfy the explicit constraints
define a possible solution space for I.
Definition 2: Implicit constraints are rules that determine which of the tuples in the
solution space of I satisfy the criterion function. Thus, implicit
constraints describe the way in which the xi’s must relate to each other.
Explicit constraints using 8-tuple formation, for this problem are S= {1, 2, 3,
4, 5, 6, 7, 8}.
The implicit constraints for this problem are that no two queens can be the
same (i.e., all queens must be on different columns) and no two queens can
be on the same diagonal.
Backtracking is the procedure where by, after determining that a node can lead to
nothing but dead end, we go back (backtrack) to the nodes parent and proceed with
the search on the next child.
A backtracking algorithm need not actually create a tree. Rather, it only needs to
keep track of the values in the current branch being investigated. This is the way we
implement backtracking algorithm. We say that the state space tree exists implicitly
in the algorithm because it is not actually constructed.
Terminology:
Problem state is each node in the depth first search tree.
Solution states are the problem states ‘S’ for which the path from the root node to
‘S’ defines a tuple in the solution space.
Answer states are those solution states for which the path from root node to s
defines a tuple that is a member of the set of solutions.
State space is the set of paths from root node to other nodes. State space tree is the
tree organization of the solution space. The state space trees are called static trees.
This terminology follows from the observation that the tree organizations are
independent of the problem instance being solved. For some problems it is
advantageous to use different tree organizations for different problem instance. In
this case the tree organization is determined dynamically as the solution space is
being searched. Tree organizations that are problem instance dependent are called
dynamic trees.
Live node is a node that has been generated but whose children have not yet been
generated.
E-node is a live node whose children are currently being explored. In other words, an
E-node is a node currently being expanded.
Dead node is a generated node that is not to be expanded or explored any further.
All children of a dead node have already been expanded.
Branch and Bound refers to all state space search methods in which all children of
an E-node are generated before any other live node can become the E-node.
Depth first node generation with bounding functions is called backtracking. State
generation methods in which the E-node remains the E-node until it is dead, lead to
branch and bound methods.
Planar Graphs:
N-Queens Problem:
All solutions to the 8-queens problem can be represented as 8-tuples (x1, . . . . , x8),
where xi is the column of the ith row where the ith queen is placed.
The explicit constraints using this formulation are Si = {1, 2, 3, 4, 5, 6, 7, 8}, 1 < i <
8. Therefore the solution space consists of 88 8-tuples.
The implicit constraints for this problem are that no two xi’s can be the same (i.e., all
queens must be on different columns) and no two queens can be on the same
diagonal.
This realization reduces the size of the solution space from 88 tuples to 8! Tuples.
The promising function must check whether two queens are in the same column or
diagonal:
Suppose two queens are placed at positions (i, j) and (k, l) Then:
Diag 45 conflict: Two queens i and j are on the same 450 diagonal if:
i – j = k – l.
This implies, j – l = i – k
This implies, j – l = k – i
Therefore, two queens lie on the same diagonal if and only if:
j - l = i – k
Where, j be the column of object in row i for the i th queen and l be the column of
object in row ‘k’ for the kth queen.
To check the diagonal clashes, let us take the following tile configuration:
i 1 2 3 4 5 6 7 8
xi 2 5 1 8 4 7 3 6
j - l = i – k 1 - 6 = 3 – 8
5 = 5
Example:
Step 2:
If this new sequence is feasible and has length 8 then STOP with a solution. If
the new sequence is feasible and has length less then 8, repeat Step 1.
Step 3:
If the sequence is not feasible, then backtrack through the sequence until we
find the most recent place at which we can exchange a value. Go back to Step
1.
Let us see how backtracking works on the 4-queens problem. We start with the root
node as the only live node. This becomes the E-node. We generate one child. Let us
assume that the children are generated in ascending order. Let us assume that the
children are generated in ascending order. Thus node number 2 of figure is generated
and the path is now (1). This corresponds to placing queen 1 on column 1. Node 2
becomes the E-node. Node 3 is generated and immediately killed. The next node
generated is node 8 and the path becomes (1, 3). Node 8 becomes the E-node.
However, it gets killed as all its children represent board configurations that cannot
lead to an answer node. We backtrack to node 2 and generate another child, node 13.
The path is now (1, 4). The board configurations as backtracking proceeds is as
follows:
1 1 1 1
. . 2 2 2
. . . . . 3
1 1 1 1
2 . . . 2 2
3 3
. . . . . . 4
(e) (f) (g) (h)
The above figure shows graphically the steps that the backtracking algorithm goes
through as it tries to find a solution. The dots indicate placements of a queen, which
were tried and rejected because another queen was attacking.
In Figure (b) the second queen is placed on columns 1 and 2 and finally settles on
column 3. In figure (c) the algorithm tries all four columns and is unable to place the
next queen on a square. Backtracking now takes place. In figure (d) the second
queen is moved to the next possible column, column 4 and the third queen is placed
on column 2. The boards in Figure (e), (f), (g), and (h) show the remaining steps that
the algorithm goes through until a solution is found.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 7
Unit - IV
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
Sum of Subsets-CO4
Given positive numbers wi, 1 ≤ i ≤ n, and m, this problem requires finding all subsets
of wi whose sums are ‘m’.
Explicit constraints:
Implicit constraints:
The above solutions are then represented by (1, 1, 0, 1) and (0, 0, 1, 1).
For both the above formulations, the solution space is 2n distinct tuples.
For example, n = 4, w = (11, 13, 24, 7) and m = 31, the desired subsets are (11,
13, 7) and (24, 7).
The tree corresponds to the variable tuple size formulation. The edges are labeled
such that an edge from a level i node to a level i+1 node represents a value for x i. At
each node, the solution space is partitioned into sub - solution spaces. All paths from
the root node to any node in the tree define the solution space, since any such path
corresponds to a subset satisfying the explicit constraints.
The possible paths are (1), (1, 2), (1, 2, 3), (1, 2, 3, 4), (1, 2, 4), (1, 3, 4), (2), (2,
3), and so on. Thus, the left mot sub-tree defines all subsets containing w1, the next
sub-tree defines all subsets containing w2 but not w1, and so on.
Let G be a graph and m be a given positive integer. We want to discover whether the
nodes of G can be colored in such a way that no two adjacent nodes have the same
color, yet only m colors are used. This is termed the m-colorabiltiy decision problem.
The m-colorability optimization problem asks for the smallest integer m for which the
graph G can be colored.
Given any map, if the regions are to be colored in such a way that no two adjacent
regions have the same color, only four colors are needed.
For many years it was known that five colors were sufficient to color any map, but no
map that required more than four colors had ever been found. After several hundred
years, this problem was solved by a group of mathematicians with the help of a
computer. They showed that in fact four colors are sufficient for planar graphs.
The function m-coloring will begin by first assigning the graph to its adjacency matrix,
setting the array x [] to zero. The colors are represented by the integers 1, 2, . . . , m
and the solutions are given by the n-tuple (x1, x2, . . ., xn), where xi is the color of
node i.
A recursive backtracking algorithm for graph coloring is carried out by invoking the
statement mcoloring(1);
Hamiltonian Cycles:
Graph G1 Graph G2
The backtracking solution vector (x1, . . . . . xn) is defined so that xi represents the ith
visited vertex of the proposed cycle. If k = 1, then x1 can be any of the n vertices. To
avoid printing the same cycle n times, we require that x1 = 1. If 1 < k < n, then xk
can be any vertex v that is distinct from x1, x2, . . . , xk–1 and v is connected by an
edge to kx-1. The vertex xn can only be one remaining vertex and it must be connected
to both xn-1 and x1.
The traveling salesperson problem using dynamic programming asked for a tour that
has minimum cost. This tour is a Hamiltonian cycles. For the simple case of a graph
all of whose edge costs are identical, Hamiltonian will find a minimum-cost tour if a
tour exists.
Branch and Bound is another method to systematically search a solution space. Just
like backtracking, we will use bounding functions to avoid generating subtrees that
do not contain an answer node. However branch and Bound differs from backtracking
in two important manners:
1. It has a branching function, which can be a depth first search, breadth first
search or based on bounding function.
2. It has a bounding function, which goes far beyond the feasibility test as a
mean to prune efficiently the search tree.
Branch and Bound refers to all state space search methods in which all children of
the E-node are generated before any other live node becomes the E-node
Branch and Bound is the generalization of both graph search strategies, BFS and D-
search.
A BFS like state space search is called as FIFO (First in first out) search
as the list of live nodes in a first in first out list (or queue).
A D search like state space search is called as LIFO (Last in first out)
search as the list of live nodes in a last in first out (or stack).
Definition 1: Live node is a node that has been generated but whose children have
not yet been generated.
Definition 2: E-node is a live node whose children are currently being explored. In
other words, an E-node is a node currently being expanded.
Definition 4: Branch-an-bound refers to all state space search methods in which all
children of an E-node are generated before any other live node can
become the E-node.
173
Least Cost (LC) search:
In both LIFO and FIFO Branch and Bound the selection rule for the next E-node in
rigid and blind. The selection rule for the next E-node does not give any preference
to a node that has a very good chance of getting the search to an answer node
quickly.
The search for an answer node can be speeded by using an “intelligent” ranking
function c( ) for live nodes. The next E-node is selected on the basis of this ranking
function. The node x is assigned a rank using:
c( x ) = f(h(x)) + g( x )
h(x) is the cost of reaching x from the root and f(.) is any non-decreasing
function.
A search strategy that uses a cost function c( x ) = f(h(x) + g( x ) to select the next
E-node would always choose for its next E-node a live node with least c(.) is called a
LC–search (Least Cost search)
BFS and D-search are special cases of LC-search. If g( x ) = 0 and f(h(x)) = level of
node x, then an LC search generates nodes by levels. This is eventually the same as
a BFS. If f(h(x)) = 0 and g( x ) > g( y ) whenever y is a child of x, then the search is
essentially a D-search.
We associate a cost c(x) with each node x in the state space tree. It is not possible to
easily compute the function c(x). So we compute a estimate c( x ) of c(x).
Let t be a state space tree and c() a cost function for the nodes in t. If x is a node in
t, then c(x) is the minimum cost of any answer node in the subtree with root x. Thus,
c(t) is the cost of a minimum-cost answer node in t.
A heuristic c(.) is used to estimate c(). This heuristic should be easy to compute and
generally has the property that if x is either an answer node or a leaf node, then
c(x) = c( x ) .
LC-search uses c to find an answer node. The algorithm uses two functions Least() and
Add() to delete and add a live node from or to the list of live nodes, respectively.
Least() finds a live node with least c(). This node is deleted from the list of live nodes
and returned.
174
Add(x) adds the new live node x to the list of live nodes. The list of live nodes be
implemented as a min-heap.
Algorithm LCSearch outputs the path from the answer node it finds to the root node
t. This is easy to do if with each node x that becomes live, we associate a field parent
which gives the parent of node x. When the answer node g is found, the path from g
to t can be determined by following a sequence of parent values starting from the
current E-node (which is the parent of g) and ending at node t.
Listnode = record
{
Listnode * next, *parent; float cost;
}
Algorithm LCSearch(t)
{ //Search t for an answer node
if *t is an answer node then output *t and return;
E := t; //E-node.
initialize the list of live nodes to be empty;
repeat
{
for each child x of E do
{
if x is an answer node then output the path from x to t and return;
Add (x); //x is a new live node.
(x parent) := E; // pointer for path to root
}
if there are no more live nodes then
{
write (“No answer node”);
return;
}
E := Least();
} until (false);
}
The root node is the first, E-node. During the execution of LC search, this list
contains all live nodes except the E-node. Initially this list should be empty.
Examine all the children of the E-node, if one of the children is an answer node, then
the algorithm outputs the path from x to t and terminates. If the child of E is not an
answer node, then it becomes a live node. It is added to the list of live nodes and its
parent field set to E. When all the children of E have been generated, E becomes a
dead node. This happens only if none of E’s children is an answer node. Continue the
search further until no live nodes found. Otherwise, Least(), by definition, correctly
chooses the next E-node and the search continues from here.
LC search terminates only when either an answer node is found or the entire state
space tree has been generated and searched.
Bounding:
A branch and bound method searches a state space tree using any search
mechanism in which all the children of the E-node are generated before another node
becomes the E-node. We assume that each answer node x has a cost c(x) associated
with it and that a minimum-cost answer node is to be found. Three common search
strategies are FIFO, LIFO, and LC. The three search methods differ only in the
selection rule used to obtain the next E-node.
175
A good bounding helps to prune efficiently the tree, leading to a faster exploration of
the solution space.
A cost function c(.) such that c( x ) < c(x) is used to provide lower bounds on
solutions obtainable from any node x. If upper is an upper bound on the cost of a
minimum-cost solution, then all live nodes x with c(x) > c( x ) > upper. The starting
value for upper can be obtained by some heuristic or can be set to .
As long as the initial value for upper is not less than the cost of a minimum-cost
answer node, the above rules to kill live nodes will not result in the killing of a live
node that can reach a minimum-cost answer node. Each time a new answer node is
found, the value of upper can be updated.
To formulate the search for an optimal solution for a least-cost answer node in a
state space tree, it is necessary to define the cost function c(.), such that c(x) is
minimum for all nodes representing an optimal solution. The easiest way to do this is
to use the objective function itself for c(.).
For nodes representing feasible solutions, c(x) is the value of the objective
function for that feasible solution.
For nodes representing partial solutions, c(x) is the cost of the minimum-cost
node in the subtree with root x.
Since, c(x) is generally hard to compute, the branch-and-bound algorithm will use an
estimate c( x ) such that c( x ) < c(x) for all x.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 2
Unit - V
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
A FIFO branch-and-bound algorithm for the job sequencing problem can begin with
upper = as an upper bound on the cost of a minimum-cost answer node.
Starting with node 1 as the E-node and using the variable tuple size formulation of
Figure 8.4, nodes 2, 3, 4, and 5 are generated. Then u(2) = 19, u(3) = 14, u(4) =
18, and u(5) = 21.
The variable upper is updated to 14 when node 3 is generated. Since c (4) and c(5)
are greater than upper, nodes 4 and 5 get killed. Only nodes 2 and 3 remain alive.
Node 2 becomes the next E-node. Its children, nodes 6, 7 and 8 are generated.
Then u(6) = 9 and so upper is updated to 9. The cost c(7) = 10 > upper and node 7
gets killed. Node 8 is infeasible and so it is killed.
Next, node 3 becomes the E-node. Nodes 9 and 10 are now generated. Then u(9) =
8 and so upper becomes 8. The cost c(10) = 11 > upper, and this node is killed.
The next E-node is node 6. Both its children are infeasible. Node 9’s only child is also
infeasible. The minimum-cost answer node is node 9. It has a cost of 8.
An LC Branch-and-Bound search of the tree of Figure 8.4 will begin with upper =
and node 1 as the first E-node.
Node 2 is the next E-node as c(2) = 0 and c(3) = 5. Nodes 6, 7 and 8 are generated
and upper is updated to 9 when node 6 is generated. So, node 7 is killed as c(7) = 10
> upper. Node 8 is infeasible and so killed. The only live nodes now are nodes 3 and
6.
Node 6 is the next E-node as c(6) = 0 < c(3) . Both its children are infeasible.
Node 3 becomes the next E-node. When node 9 is generated, upper is updated to 8
as u(9) = 8. So, node 10 with c(10) = 11 is killed on generation.
Node 9 becomes the next E-node. Its only child is infeasible. No live nodes remain.
The search terminates with node 9 representing the minimum-cost answer node.
2 3
The path = 1 3 9 = 5 + 3 = 8
By using dynamic programming algorithm we can solve the problem with time
complexity of O(n22n) for worst case. This can be solved by branch and bound
technique using efficient bounding function. The time complexity of traveling sale
person problem using LC branch and bound is O(n 22n) which shows that there is no
change or reduction of complexity than previous method.
We start at a particular node and visit all nodes exactly once and come back to initial
node with minimum cost.
Let G = (V, E) is a connected graph. Let C(i, J) be the cost of edge <i, j>. cij = if
<i, j> E and let |V| = n, the number of vertices. Every tour starts at vertex 1 and
ends at the same vertex. So, the solution space is given by S = {1, , 1 | is a
permutation of (2, 3, . . . , n)} and |S| = (n – 1)!. The size of S can be reduced by
restricting S so that (1, i 1, i2, . . . . in-1, 1) S iff <ij, ij+1> E, 0 < j < n - 1 and i0
= in =1.
1. Reduce the given cost matrix. A matrix is reduced if every row and column is
reduced. A row (column) is said to be reduced if it contain at least one zero and
all-remaining entries are non-negative. This can be done as follows:
a) Row reduction: Take the minimum element from first row, subtract it
from all elements of first row, next take minimum element from the
second row and subtract it from second row. Similarly apply the same
procedure for all rows.
b) Find the sum of elements, which were subtracted from rows.
c) Apply column reductions for the matrix obtained after row reduction.
e) Obtain the cumulative sum of row wise reduction and column wise
reduction.
2. Calculate the reduced cost matrix for every node R. Let A is the reduced cost
matrix for node R. Let S be a child of R such that the tree edge (R, S)
corresponds to including edge <i, j> in the tour. If S is not a leaf node, then
the reduced cost matrix for S may be obtained as follows:
b) Set A (j, 1) to .
c) Reduce all rows and columns in the resulting matrix except for rows and
column containing only . Let r is the total amount subtracted to reduce
the matrix.
c) Find cS cR A i, j r, where ‘r’ is the total amount subtracted
to reduce the matrix, cR indicates the lower bound of the ith node in (i,
j) path and c S is called the cost function.
Consider the instance: M = 15, n = 4, (P1, P2, P3, P4) = (10, 10, 12, 18) and
(w1, w2, w3, w4) = ( 2, 4, 6, 9).
0/1 knapsack problem can be solved by using branch and bound technique. In this
problem we will calculate lower bound and upper bound for each node.
Place first item in knapsack. Remaining weight of knapsack is 15 – 2 = 13. Place next
item w2 in knapsack and the remaining weight of knapsack is 13 – 4 = 9. Place next
item w3 in knapsack then the remaining weight of knapsack is 9 – 6 = 3. No fractions
are allowed in calculation of upper bound so w4 cannot be placed in knapsack.
Profit = P1 + P2 + P3 = 10 + 10 + 12
So, Upper bound = 32
To calculate lower bound we can place w4 in knapsack since fractions are allowed in
calculation of lower bound.
3
Lower bound = 10 + 10 + 12 + ( X 18) = 32 + 6 = 38
9
Knapsack problem is maximization problem but branch and bound technique is
applicable for only minimization problems. In order to convert maximization problem
into minimization problem we have to take negative sign for upper bound and lower
bound.
CVR COLLEGE OF ENGINEERING
An UGC Autonomous Institution - Affiliated to JNTUH
Handout – 4
Unit - V
Year and Semester: IIyr &II Sem
A Subject: Design and Analysis of Algorithms
Branch: CSE
Faculty: Dr. N. Subhash Chandra, Professor of CSE
The problems has best algorithms for their solutions have “Computing times”, that
cluster into two groups
Group 1 Group 2
No one has been able to develop a polynomial time algorithm for any problem in the
2nd group (i.e., group 2)
So, it is compulsory and finding algorithms whose computing times are greater than
polynomial very quickly because such vast amounts of time to execute that even
moderate size problems cannot be solved.
Theory of NP-Completeness:
Show that may of the problems with no polynomial time algorithms are computational
time algorithms are computationally related.
There are two classes of non-polynomial time problems
1. NP-Hard
2. NP-Complete
NP Complete Problem: A problem that is NP-Complete can solved in polynomial time
if and only if (iff) all other NP-Complete problems can also be solved in polynomial time.
NP-Hard: Problem can be solved in polynomial time then all NP-Complete problems can
be solved in polynomial time.
All NP-Complete problems are NP-Hard but some NP-Hard problems are not know to be NP-
Complete.
Nondeterministic Algorithms:
Algorithms with the property that the result of every operation is uniquely defined are
termed as deterministic algorithms. Such algorithms agree with the way programs are
executed on a computer.
Algorithms which contain operations whose outcomes are not uniquely defined but
are limited to specified set of possibilities. Such algorithms are called
nondeterministic algorithms.
The machine executing such operations is allowed to choose any one of these
outcomes subject to a termination condition to be defined later.
sful completion
P
polynomial time.
is the set of all decision problems solvable by nondeterministic algorithms
in polynomial time.
If there any single problem in NP, such that if we showed it to be in ‘P’ then that
would imply that P=NP.
This implies that, if we have a polynomial time algorithm for L 2, Then we can solve L1 in
polynomial time.
L1 α L2 and L2 α L3 then L1 α L3
q(p3(n)log n)).
If satisfiability is ‘p’, then ‘q(m)’ is a polynomial function of ‘m’ and the
complexity of ‘Z’ becomes ‘O(r(n))’ for some polynomial ‘r()’.