Beruflich Dokumente
Kultur Dokumente
1. Introduction
1.1 Notion of Algorithm
1.2 Fundamentals of Algorithmic Problem Solving
1.3 Important Problem Types
2. Analysis of Algorithm Efficiency
2.1 Analysis Framework
2.2 Asymptotic Notations and Basic Efficiency Classes
2.3 Mathematical Analysis of Non Recursive Algorithms
2.4 Mathematical Analysis of the Recursive Algorithms
2.5 Example - Fibonacci Numbers
3. Brute Force
3.1 Selection Sort
3.2 Bubble Sort
3.3 Sequential Search
3.4 Brute Force String Matching
3.5 Closes-Pair and Convex- Hull Problems by Brute-Force String
Matching
3.6 Exhaustive Search
4. Divide and Conquer
4.1 Merge Sort
4.2 Quick Sort
4.3 Binary Search
4.4 Binary Tree Traversals
4.5 Strassens Matrix Multiplication
4.6 Closest-Pair and Convex-Hull Problem
5. Decrease and Conquer
5.1 Insertion Sort
5.2 Depth-First Search and Breadth-First Search
5.3 Topological Sorting
6. Transform and Conquer
6.1 Presorting
6.2 Horners Rule
Ex: gcd (60,24) = gcd (24, 60 mod 24) = gcd (24, 12) = gcd (12, 24 mod 12)
= gcd (12, 0) = 12
Step 1: Start
Step 2: If n is equal to zero then go to step 6
Step 3: Divide m by n and assign the value of the remainder to rem
Step 4: Assign the value of n to m and the value of rem to n
Step 5: go to Step 2
Step 6: Print the value of m
Step 7: Stop
ALGORITHM: Euclid ( m, n )
// Computes gcd ( m, n ) by Euclids algorithm
// Input: Two positive integers, not both zero integers m and n
// Output: Greatest common divisor of m and n
while n 0 do
r m mod n
m n
nr
return m
Fig 1.2
5. Designing an algorithm
An algorithm design technique is a general approach to solving
problems algorithmically that is applicable to variety of
problems from different areas of computing.
These design techniques provide guidance for designing
algorithms for new problems, i.e. problems for which there is
no known satisfactory algorithm.
Algorithm design technique makes it possible to classify
algorithms according to an underlying design idea, therefore
they can serve as a natural way to both categorize and study
algorithms.
It
can
be
considered
as
algorithms
implementation.
8. Analyzing an Algorithm
Analysis of algorithms or performance analysis refers to the
task of determining how much computing time and storage an
algorithm requires.
There are two kinds of algorithm efficiency. They are time
efficiency and space efficiency.
Time efficiency indicates how fast the algorithm runs.
9. Coding an Algorithm
Now the program can be written. This phase is referred to as
program proving or sometimes called program verification.
Once a program is written we should know how to test a
program. Testing program consist of two phases: debugging
and profiling (or performance measurement).
Debugging is the process of executing programs on sample data
sets to determine whether faulty results occur and correct them
if so. Debugging can point to the presence of errors but not to
their absence.
Profiling or performance measurement is the process of
executing a correct program on data sets and measuring the
time and space it takes to compute the results.
Verification for the inputs should be provided while
implementing algorithms.
1.
Sorting
Arranging the items in either ascending or descending order is
called sorting
Usually lists of numbers, characters, character strings and records
will have to be sorted
Sorting is useful in many areas. The most important is searching
E.g.: Arranging the names of students in the attendance register in
alphabetical order.
Two properties of sorting need special attention
2.
Searching
Finding a given value, called search key, in a given list is called
Searching
E.g.: Searching a telephone number in a telephone directory.
Searching has to be considered in conjunction with two other
operations: addition to and deletion from the data set of an item. In
3.
String Processing
A string is a sequence of characters
Different types of strings are:
Text Strings Consists of letters, numbers and special
characters. E.g.: apple, 123, 1@xyz
Bit Strings Consists of zeros and ones.
E.g.: 1010,
111000111, 001
Some of the important string processing problems are:
String matching: Searching for a given word in a text
String concatenation: Adding one string to the end of
another string
String copy: Copying one string to another
4.
Graph problems
A graph is a collection of points called vertices, some of which are
connected by line segments called edges
Graphs are used to model a wide variety of real-life applications,
including transportation and communication networks, project
scheduling, and games
Basic graph algorithms include:
5.
Combinatorial problems
a combinatorial object such as a permutation, a combination or a
subset that satisfies certain constraints and has some desired property
They are the most difficult problems because of the following reasons:
The number of combinatorial objects grows extremely fast with
a problems size
There are no known algorithms for solving most such problems
exactly in an acceptable amount of time
The traveling salesman problem and graph coloring problem are
examples of combinatorial problems
6.
Geometric problems
They deal with geometric objects such as points, lines, and polygons
Some of the geometric problems include constructing simple
geometric shapes like triangles, circle etc., closest-pair problem,
convex hull problem etc.
They find applications in computer graphics, robotics, and
tomography
7.
Numerical problems
Solving mathematical objects of continuous nature such as solving
equations and systems of equations, computing definite integrals,
evaluating functions and so on
Most of such problems can be solved only approximately
They play important role in scientific and engineering applications
b = log2 n + 1
T (2n)
cop * C (2n)
-------
--------------- ----------
T (n)
cop * C (n)
= 4
n2
3. Orders of Growth
It specifies the effect on an algorithms performance by the variation
in the input size
Example: A twofold increase in the input size, n will cause the
logarithmic functions to increase by a value of 1, linear function by
twofold, quadratic function by fourfold and so on
The counts order of growth for large input sizes is important than
small input sizes because, a difference in running times on small
inputs is not what really distinguishes efficient algorithms from
inefficient ones
The logarithmic functions are the functions growing the slowest,
whereas, the exponential and factorial functions grow so fast that their
values become astronomically large even for small values of n.
The running time of an algorithm not only depends on the input size
but also on the nature of the input on certain occasions
Depending on the nature of the input an algorithm can have three
kinds of efficiencies
Worst-Case efficiency
It is the efficiency of an algorithm when it runs the longest
among all possible inputs of size n
To determine this, find the inputs that yield the largest value of
the basic operations count
It bounds the running time from above
Best-Case efficiency
It is the efficiency of an algorithm when it runs the fastest
among all possible inputs of size n
To determine this, find the inputs that yield the smallest value
of the basic operations count
It bounds the running time from below
Average-Case efficiency
It is the efficiency of an algorithm on random inputs
To determine this, some assumptions about possible inputs of
size n have to be made
It is important because there are many algorithms for which the
average-case efficiency is much better than the worst-case
efficiency would lead us to believe
Example: Consider the sequential search algorithm given below
ALGORITHM SequentialSearch (A[0, ...,n 1], K)
i0
Definition: O notation
A function t(n) is said to be in O(g(n)), denoted by t(n) O(g(n)), if t(n) is
bounded above by some constant multiple of g(n) for all large n, i.e., if there
exist some positive constant c and some nonnegative integer n0 such that t(n)
cg(n) for all n n0
for all n n0
To prove:
100 * n + 5 O(n2)
100 * n + 5 100 * n + n
for all n 5
101 * n
101 * n2
Thus C = 101 and n0 5
2)
Let f(n) = (3 * n) + 3
O(n) be worst case for the algorithm.
To prove:
(3 * n) + 3 O(n)
(3 * n) + 3 (3 * n) + n for all n 3
4n.
Thus C = 4 and n0 = 3.
The definition gives us a lot of freedom in choosing specific values
for constants c and n0
Definition 2:
notation
for all n n0
To Prove: n3 (n2)
n3 n2
for all n 0
for all n 0
thus C = 1 n0 = 0.
for all n 0
Definition 3: notation
A function t(n) is said to be in (g(n)), denoted by t(n) (g(n)), if t(n) is
bounded both above and below by some positive constant multiples of g(n)
for all large n, ie, if there exist some positive constant c1 and c2 some
nonnegative integer n0 such that c2g(n) t(n) c1g(n) for all n n0
for all n 0
or
f(n) C1 * g(n)
* n * (n - 1) (n2) 1 / 2 * n
* n2 1 / 2 * n * 1 / 2 * n
* n2 1 / 4 * n2
for all n 2
* n2
C2 =
and
C1 = 1 / 2
n0 = 2
C2 = 1 / 4 and n0 = 2.
Proof:
t1(n) O(g1(n)) t1(n) c1 g1(n) for all n n1
(1)
(2)
[because c3 = max{ c1 , c2 } ]
c3 [ g1(n) + g2(n) ]
2 c3 max { g1(n) , g2(n) }
t1(n) + t2(n) O( max { g1(n) , g2(n) })
limn
_
t(n)/g(n) =
n (n 1)
1 lim
-------------- = --- n
n2
2
= 1 / 2 lim
n
n2 - n
------n2
(1 1 / n) = 1 / 2
Class
Name
Comments
constant
Log n
logarithmic
linear
n log n
n-log-n
Many
divide-and-conquer
algorithms,
quadratic
Typically,
characterizes
efficiency
of
examples.
n3
cubic
Typically,
characterizes
efficiency
of
exponential
n!
factorial
Explanation:
Assume the first element in the array to be the largest element and
assume it to maxval
maxval A [0]
In the for loop compare the maxval with the remaining elements of the
array one after the other and overwrite the maxval if any of the array
elements happen to be greater than maxval
Since the execution of the for loop is completed, return the largest
value that is stored in maxval
Analysis:
Input Size: - Number of elements in the array, n.
Basic Operation: - Key Comparison operation
if A[i] > maxval.
C(n) =
Example 2: Finding the Uniqueness problem, to check whether all the
elements in a given array are distinct
ALGORITHM
Explanation:
In the first pass it compares the first element with all the remaining
elements in the array (starting from the second element) and returns
false if any of the elements is equal to the first element.
In the second pass it compares the second element with all the
remaining elements in the array (starting from the third element) and
returns false if any of the elements is equal to the second element.
Analysis:
Input Size: - The number of elements in the array, n.
Basic Operation: - Key Comparison operation if A[i] = A [j]
The number of times the key comparison operation is performed
depends on the positions of the equal elements, hence the algorithm
has best case, worst case and average case
Let C(n) be the number of times the key comparison operation
performed.
Best Case:
It occurs when the first two elements in the array are equal.
Hence the key comparison operation will be executed only
once.
i.e. C(n) = 1 (1)
It occurs when the last two elements in the array are equal.
Hence the key comparison operation will be executed
maximum number of times.
n-2
n-1
i=0
j=i+1
C(n)=
i.e.
n-2
=
n 1 (i + 1) + 1
i=0
n-2
=
ni1
i=0
= (n 0 - 1) + (n 1 - 1) + + (n (n 2) 1)
= (n 1) + (n 2) + + 1
= (n 1) (n 1 + 1) / 2
= n (n 1) / 2
C(n) (n2)
0...n - 1])
//Multiplies two square matrices of order n by the definition-based
//algorithm
//Input: Two n-by-n matrices A and B
//Output: Matrix C = AB
for i 1 to n do
for j 1 to n do
C [i, j] 0.0
for k 1 to n do
C [i, j ] C [i, j] + A [i, k] * B [k, j]
return C
Explanation:
The i loop indicates the row, j loop indicates the column and k loop
acts as an index of the column in the first matrix and index of the row
in the second matrix that are to be multiplied.
In the k loop, the matrix product is found as follows:
When k = 0, A[i, k] * B[k, j] multiplies the element in the first
column of the ith row with the element in the first column of the
jth column.
When k = 1, A[i, k] * B[k, j] multiplies the element in the
second column of the ith row with the element in the second
column of the jth row and adds it to partial product stored in
c[i, j].
During each iteration of the k loop the corresponding elements
in the ith row and the jth column are multiplied and product
obtained is added to the partial product produced so far, which
is stored in C [i, j].
Execution of the k loop for every value of i and j, computes one
corresponding value of the product matrix C.
Analysis:
Input Size: - Order of the matrix, n.
Basic Operation: - The multiplication operation A[i, k] * B[k, j]
C(n) =
i=1 j=1
n
=
n2
i=1
= n3
C(n) (n3)
ALGORITHM: Factorial(n)
//Computes n! recursively.
for n 1.
Explanation:
If the given input is 0, it returns the result 1
If the given input is any positive number other than 0, then recursively
computes F(n) = F(n 1) * n
Analysis:
Input Size: - The number n whose factorial is to be found.
Basic operation: Multiplication operation F(n 1) * n
Let C(n) denote the number of times the multiplication operation is
executed.
F(n) is computed using the formula F(n) = F(n 1) * n. Since we
dont know how many times the multiplication operation is performed
within the call F(n 1), let us denote it by C(n 1) and after finding
out F(n 1), one multiplication is performed to find F(n). Therefore,
the following recurrence relation gives the number of times the basic
operation is executed.
C(n) = C(n 1) + 1
else
Hanoi (source, destination, temp, n 1)
Move nth disk from source to destination
Hanoi (temp, source, destination, n - 1)
Fig 2.1
Explanation:
Moves n 1 disks recursively form the source peg to the auxiliary peg
using destination peg as temporary
Moves the nth disk from source to the destination
Moves the n 1 disks recursively which are in the auxiliary peg to the
destination peg using source as the temporary
The above three steps are shown in the Fig 2.1 above.
Analysis 1:
Input size: The number of disks, n.
Basic operation: Disk move operation from one peg to another
n-1
= 2i
i=0
= 2n 1 (2n)
Analysis 2:
The number of times the recursive calls made and hence the number
of times the disk is moved can also be represented by a complete
binary tree as shown in the Fig 2.2 below.
We know that the number of nodes in a complete binary tree is 2n 1.
Hence the efficiency of Tower of Hanoi (2n)
Fig. 2.2
Example 3: Counting the binary digits
Explanation:
To convert a decimal integer to its equivalent binary form, we divide
the integer by 2 and each such division gives us one binary digit.
Hence in the else part of the algorithm the integer n is divided by 2,
count of the number of binary digits is incremented by one and the
divided number is passed as an argument to the function recursively
until the integer becomes equal to 1.
When n becomes equal to 1 it constitutes the last binary digit of n and
hence 1 is returned to add 1 to the accumulated count of the number of
binary digits.
Analysis:
Input size: The integer n.
Basic operation: Addition operation BinRec(n / 2) + 1
Let C(n) be the number of times the division operation is
performed.
Let C(n / 2) represent the number of times the addition operation is
performed in the recursive call BinRec(n / 2). One more addition
operation is performed to add one after returning from the
recursive call. Hence, C(n) = C(n / 2) + 1.
When n becomes 1, no addition operation is performed. Hence the
initial condition is C(1) = 0.
Now, solving the recurrence C(n) = C(n / 2) + 1, we get
C(n) = C(n / 2) + 1
Let n = 2k
Therefore, k = log2n
C(2k) = C(2k-1) + 1
= C(2k-2) + 2
= C(2k-3) + 3
=
=
=
= C(2k-i) + I
=
=
=
when i = k, we get
= C(2k-k) + k
= C(1) + k
=k
we know that n = 2k and k = log2n
= log2 n
C(n) (log n)
If the first two Fibonacci numbers are represented as F(0) = 0 and F(1)
= 1, the Fibonacci sequence can be generated by the recurrence F(n) =
F(n-1) + F(n-2).
The Fibonacci recurrence and the recurrence used to analyze the
efficiency of the recursive algorithm to find the nth Fibonacci number
are examples of a homogeneous second-order linear recurrence with
constant coefficients. Hence it is necessary to know how to solve a
homogeneous
second-order
linear
recurrence
with
constant
coefficients.
Homogeneous second-order linear recurrence with constant coefficients
A recurrence of the form ax( n ) + bx ( n 1 ) + cx ( n 2 ) = 0 is
called as a homogenous second-order linear recurrence with constant
coefficients
Homogeneous Since ax (n) + bx (n 1) + cx (n 1) is equal to
zero
Second-order The elements x (n) and x (n 2) are two positions
apart
Linear The terms are a linear combination of the unknown terms
To solve this recurrence, a quadratic equation with the same
coefficients as the recurrence, called as a characteristic equation is
used
Characteristic equation: ar2 + br + c = 0
If r1 and r2 are the roots of the characteristic equation, then the
solution to the recurrence is obtained as follows
If r1 and r2 are real and distinct, then
x (n) = r1n + r2n
If r1 and r2 are equal, then
x (n) = rn + n rn
If r1 = r2 = u iv, then
x ( n ) = n ( cosn + sinn )
Where, and are two arbitrary constants,
= (u2 + v2) and
= arctan (v / u)
= --------------
1 5
=
----------
1 + 5
r1 = ---------2
1 - 5
r2 = ---------2
The roots are real and distinct, hence
F ( n ) = (( 1 + 5 ) / 2) n + (( 1 - 5 ) / 2) n
Since F (0) = 0,
(( 1 + 5 ) / 2)0 + (( 1 - 5 ) / 2)0 = 0
+ = 0
Since F (1) = 1,
---------- (1)
(( 1 + 5 ) / 2) 1 + (( 1 - 5 ) / 2) 1 = 1
( 1 + 5 ) + ( 1 - 5 ) = 2
---------- (2)
= 1 / 5
Therefore,
F(n) = 1 / 5 ((1 + 5) / 2) n - 1 / 5 ((1 - 5) / 2) n
= 1 / 5 (n - n)
Where, = (1 + 5) / 2 (known as golden ratio)
= (1 - 5) / 2
Example: To find the nth Fibonacci number
ALGORITHM: Fib(n)
if n 1
return n
else
return [Fib(n 1) + Fib(n 2)]
Explanation:
If n is equal to 0 or 1 it is returned as it is since it is the 0th and 1st
Fibonacci number respectively
Analysis:
Input size: The number n.
Basic operation: Addition operation Fib(n 1) + Fib(n 2)
Let C(n) be the number of times the addition operation is executed.
Let C(n 1) represent the number of times the addition operation is
executed in the recursive call Fib(n 1) and C(n 2) represent the
number of times the addition operation is executed in the recursive
call Fib(n 2).
After finding Fib(n 1) and Fib(n 2) one more addition is
performed to find the nth Fibonacci number. Hence, the recurrence is
C(n) = C(n 1) + C(n 2) + 1.
When n is equal to 0 or 1, no addition operation is performed. Hence
the initial conditions are C(0) = 0 and C(1) = 0.
Now, solving the recurrence C(n) = C(n - 1) + C(n 2) + 1, we get
C(n) = C(n - 1) + C(n 2) + 1
C(n) C(n 1) C(n 2) = 1
Since the RHS = 1, it is an inhomogeneous second-order linear
recurrence with constant coefficients.
------ ( 1 )
------ ( 2 )
------ ( 3 )
From ( 2 ) & ( 3 )
C(n) = F(n + 1) 1
= 1 / 5 (( 1 + 5 ) / 2) n+1 - 1 / 5 (( 1 - 5 ) / 2) n+1 1
= 1 / 5 {(( 1 + 5 ) / 2) n+1 - (( 1 - 5 ) / 2) n+1 } 1
= 1 / 5 [ n+1 - n+1 ] - 1
Advantages:
It is applicable to a wide variety of problems.
For some problems like sorting, searching, it yields reasonable
algorithms of at least some practical value with no limitation on
instance size.
The expense of designing a more efficient algorithm may be
unjustifiable if only a few instances of a problem need to be solved.
Even if too inefficient in general, a brute force algorithm can still be
useful for small size instances of a problem.
Examples:
1. Computing gcd(m,n)
2. Computing n!
3. Multiplying two matrices
4. Searching for a key of a given value in a list
5. Sorting the numbers or alphabets in ascending or descending order
6. String Matching
Explanation:
During the first pass, scan the array to find its smallest element and
swap it with the first element.
During the second pass start with the second element, scan the
elements to the right of it to find the smallest among them and swap it
with the second elements.
Generally, on pass i (0 i n-2), find the smallest element in A[i..n-1]
and
swap
it
with
A[i]:
Example:
89
1 pass
45
17
68
45
90
68
29
90
34
29
17
34
89
2 pass
17
29
68
90
3 pass
17
29
34
90
4 pass
17
29
34
45
5 pass
17
6 pass
17
29
29
34
34
45
45
45
34
68
89
68
89
90
45
68
89
68
89
90
89
90
Analysis:
Input Size: The number of elements in the array, n.
Basic operation: Key comparison operation if (a[j] < a[pos]).
Let C(n) be the number of times the key comparison operation is
executed.
The key comparison operation is executed in the innermost for loop
and is given by
n-2
n-1
C(n) =
i=0
j=i+1
n-1
n-2
= (n 1) - (i + 1) + 1
i=0
(n 1 i)
i=0
= (n 1) + (n 2) + + 1 = n * (n 1) / 2
= (n2 n) / 2 (n2).
Note: The number of key swaps is only (n) or more precisely n - 1.
Explanation:
Compare the adjacent elements of the list and exchange them if they
are out of order
During the first pass, the largest element is bubbled up to the last
position of the list.
The next pass bubbles up the second largest element and so on
Example:
89 45
68
90
29
34
17
45 89
68
90
29
34
17
45 68
89
90
29
34
17
45 68
89
90
29
34
17
45 68
89
29
90
34
17
45 68
89
29
34
90
17
45 68
89
29
34
17
90
Pass 1 End.
45 68
89
29
34
17
90
45 68
89
29
34
17
90
45 69
89
29
34
17
90
45 68
29
89
34
17
90
45 68
29
34
89
17
90
45 68
29
34
17
89
90
Analysis:
Input Size: The number of elements of the array, n.
Basic operation: Key comparison operation if A[j + 1] < A[j]
Let C(n) be the number of times the key comparison operation is
executed.
The key comparison operation is executed in the innermost for loop
and is given by
n-2 n-2-i
C( n ) =
i=0
j=0
= (n 1) + (n 2) + (n 3) + (n 4) + .. + 1
= n * (n 1) / 2
C(n) (n2)
Note: The number of key swaps depends on the input. For the worst case of
decreasing arrays, it is same as number of key comparisons.
Explanation:
The algorithm simply compares successive elements of a given list
with a given search key until either a match is encountered (successful
search) or the list is exhausted without finding a match (unsuccessful
search).
Analysis:
Input size: Number of elements in the list, n.
Basic operation: Key comparison operation A[i] k
Let C(n) be the number of times the key comparison operation is
executed.
The number of times the key comparison operation is executed not
only depends on the input size but also on the position of the search
key in the given list. Hence the algorithm has worst-case, best-case
and average-case efficiencies.
Worst-case: It occurs when the key element is not found in
the list or when the key element is found in the last location
of the list.
n
C worst (n) = 1
= n 0 + 1 = n + 1 (n)
i=0
Best-case: It occurs when the key element is found in the
first location of the list.
0
C best (n) = 1
i=0
= 0 0 + 1 = 1 (1)
match
Text T
Pattern P
pj
pm-1
Explanation:
Align the pattern against first n characters of the text.
Start matching corresponding pairs of characters from left to right
until either all the m pairs of characters match or a mismatching pair
is encountered.
Example:
Text: NOBODY NOTICED HIM
Pattern: NOT
NOBODY _NOTICED_HIM
NOT
NOT
NOT
NOT
NOT
NOT
NOT
NOT
Analysis:
Input size: The number of characters in the text, n, and the number of
characters in the pattern, m.
Basic operation: Co mparison operation P[j] = T [i + j]
Let C (n) be the number of times the comparison operation is
executed.
The number of times the comparison operation is executed depends on
the position of the pattern in the text. Hence the algorithm has worstcase, best-case and average-case efficiencies.
Worst-case:
It occurs if the following happens throughout the length of the
text: the m 1 pairs of the corresponding characters of the
text and pattern match, but a mismatch occurs at the mth pair.
n-m m-1
C worst (n) =
n-m
1 = m = m (n m + 1)
i=0 j=0
= mn m2 + m
i=0
mn (mn)
Best-case:
It occurs when the first m 1 character of the text match with
the corresponding characters of the pattern.
C best (n) =
m-1
1 = m = m (0 0 + 1)
i=0 j=0
i=0
= m (m)
Average-case:
It is shown that for random inputs, the efficiency is linear
C avg (n) = (n + m) (n)
3.5 Closes-Pair and Convex- Hull Problems by Brute-Force
String Matching
Problem statement:
Find the two Closest points in a set of n points (in the twodimensional Cartesian plane), where distance between two points pi
and pj is given by d( pi, pj ) = Sqrt ( ( xi xj )2 + ( yi yj )2 )
Explanation:
Computes
the
distance
between
every
pair
of
distinct
Analysis:
Input size: Number of points, n.
Basic operation: Finding the square in the expression d Sqrt ( ( xi
xj )2 + ( yi yj )2 ) .
Let C (n) be the number of times, square is found.
n-1
C( n ) =
i=1
n-1
j=i+1
i=1
n
1
j=i+1
n-1
i=1
j=i+1
= ni + n-i
i=1
i=1
= [ ( n 1 ) + ( n 2 ) + .. + 0 ] + [ ( n 1 ) + ( n 2 ) + .. + 0
]
= (n(n1))/2 + (n(n1))/2
= (2n (n 1)) / 2 (n2)
Convex hull
Proble m statement:
Given n points, find out the smallest convex polygon enclosing all n
points in the plane.
The convex hull of a set s of points is the smallest convex set
containing s.
Issues:
Finding the extreme points that will serve as the vertices of the
polygon.
Knowing which pairs of points need to be connected to form the
boundary of the convex hull.
Solution
A line segment connecting two points pi and pj of a set of n points is a
part of its convex hulls boundary if and only if all the other points of
the set lie on the same side of the straight line through these two
points.
Repeating the above test for every pair of points gives a list of line
segments that constitute the boundary of the convex hull.
Straight line through two points (x1, y1) and (x2, y2) is defined by the
equation ax + by = c
Where, a = y2 y1
B = x1 x2 and
C = x1y2 y1x2
To check whether all points lie on the same side of the line, check
whether the sign of the expression ax + by = c is same at each of these
points.
Analysis:
Input size: Number of points, n.
Method:
Construct a way of listing all potential solutions to the problem in a
systematic manner such that:
All solutions are eventually listed.
No solution is repeated.
Solution:
Generate the permutations of the n 1 cities leaving the city fro m
which the salesman has to start and eventually return. E.g.: If there are
four cities a, b, c, d and the starting city is a, then, generate
permutations of b, c and d, say b c d, b d c etc.
Prefix and append the starting city to each one of the generated
permutations. In the above example add a at the beginning and end
of the permutation: a b c d a, a b d c a etc.
Example:
2
2
a
8
8
5
5
b
3
3
7
7
4
4
Tour
C os t
abcda
2 + 3 + 7 + 5 = 17
abdca
2 + 4 + 7 + 8 = 21
acbda
8 + 3 + 4 + 5 = 20
acdba
8 + 7 + 4 + 2 = 21
adbca
5 + 4 + 3 + 8 = 20
adcba
5 + 7 + 3 + 2 = 17
Analysis:
Input size: The number of cities, n.
Basic operation: Generating the permutation of the intermediate n 1
Cities.
Let C (n) be the number of permutations generated.
Since we have to generate the permutations of n 1 cities,
C (n) = (n 1) ! (n!)
A close look at the generated permutations reveals that two of the
permutations are same except for the direction in which the salesman
travels. Hence, C (n) = ((n 1) ! / 2). But order of growth still belongs
to factorial class.
Proble m Statement:
Given n ite ms with:
Weights: w1, w2, . . . , wn
Values:
v1,
v2, . . . , vn
Example:
Knapsack capacity W = 16
ite m weight
value
$20
$30
10
$50
$10
Subset
Total weight
Total value
{ 1}
$20
{ 2}
$30
{ 3}
10
$50
{ 4}
$10
{1,2}
$50
{1,3}
12
$70
{1,4}
$30
{2,3}
15
$80
{2,4}
10
$40
{3,4}
15
$60
{ 1, 2, 3}
17
not feasible
{ 1, 2, 4}
12
$60
{ 1, 3, 4}
17
not feasible
{ 2, 3, 4}
20
not feasible
{ 1, 2, 3, 4}
22
not feasible
Analysis:
Input size: Number of ite ms, n.
Basic operation: Generating the subset.
Let C (n) be the number of times the subset is generated.
Since there are 2n subsets of n elements,
C (n) = 2n (2n)
Proble m Statement:
There are n people who need to be assigned to n jobs, one person per
job. The cost of assigning person i to job j is C[i,j].
Find an
Example:
J ob 0 J ob 1 J ob 2 J ob 3
Person 0
Person 1
Person 2
Person 3
Assignment
Total Cost
1, 2, 3, 4
9 + 4 + 1 + 4 = 18
1, 2, 4, 3
9 + 4 + 8 + 9 = 30
1, 3, 2, 4
9 + 3 + 8 + 4 = 24
1, 3, 4, 2
9 + 3 + 8 + 6 = 26
1, 4, 2, 3
9 + 7 + 8 + 9 = 33
1, 4, 3, 2
9 + 7 + 1 + 6 = 23
etc.
Analysis:
Input size: The number of jobs, n, and the number of people, n.
Basic operation: Generating the permutation of the n-tuple.
Let C (n) be the number of permutations generated.
Since we have to generate the permutations of a n-tuple,
C (n) = (n) ! (n!)
T(n) (nlog b a )
Explanation;
Split array A[0..n-1] into about two equal halves and make copies of
each half in arrays B and C
Sort arrays B and C recursively
Merge the sorted arrays B and C into array A as follows:
Repeat the following until no elements remain in one of the
arrays:
Compare the first elements in the remaining unprocessed
portions of the arrays
8 3 2 9
7 1 5 4
8 3
2 9
3 8
71
2 9
2 3 8 9
5 4
1 7
4 5
1 4 5 7
1 2 3 4 5 7 8 9
Analysis:
Input size: Number of elements in the array, n.
for n = 1
for n > 1
Worst Case:
It occurs when smaller elements come from alternate arrays while
merging.
So, Cmerge(n) = n - 1
Thus, C(n) = 2 C(n/2) + n 1
Let n = 2k, Therefore, k = log2 n
C(2k) = 2 C(2k-1) + 2k 1
= 2 [ 2 C(2k-2) + 2k-1 1] + 2k -1
= 22 C(2k-2) + 2k 2 + 2k 1 = 22 C(2k-2) + 2 * 2k 2
1
= 23 C(2k-3) + 3 * 2k [ 22 + 21 + 20 ]
=
=
=
= 2i C(2k-i) + i * 2k [2i-1 + + 21 + 20]
when i = k
= 2k C(1) + k * 2k [2k-1 + + 21 + 20]
= k * 2k [2k 1] (because 2k-1 + + 21 + 20 = 2k 1)
= k * 2 k 2k + 1
= log2 n * n n + 1 (because n = 2k and k = log2 n)
C(n) (n log2 n)
Best Case:
It occurs when all the elements of one of the subarrays is either
greater than the last element of the other subarray or lesser than the
first element of the other subarry.
So, Cmerge(n) = n / 2
Thus, C(n) = 2 C(n/2) + n / 2
Solving the recurrence will show that C(n) (n log2 n)
// s is a split position
Rearrange the list so that all the elements in the first s positions are
smaller than or equal to the pivot and all the elements in the remaining
n-s positions are larger than or equal to the pivot
Start comparing the pivot with a[i] and keep incrementing i until a[i]
becomes greater than pivot
40
20
23
54
15
18
85
23
78
98
Pivot i
20 < 40, therefore increment i
40
20
23
54
15
18
i
23 < 40, therefore increment i
85
23
78
98
j
40
20
85
23
78
98
j
23
54
i
15
18
54 > 40, therefore stop incrementing i and start comparing the pivot
with a[j], decrementing j until a[j] becomes less than pivot
98 > 40, therefore decrement j
40
20
23
54
15
18
i
78 > 40, therefore decrement j
40
20
23
40
20
23
85
23
78
j
98
54
15
18
85
23
78
i
j
23 < 40, Since i < j swap a[i], i.e., 54 and a[j], i.e., 23
98
54
15
18
85
23
78
98
i
j
Now continue incrementing i and decrementing j by comparing a[i]
and a[j] with the pivot respectively until i becomes greater than j
40
20
23
23
15
18
i
23 < 40, therefore increment i
85
54
j
78
98
40
20
23
23
15
18
i
15 < 40, therefore increment i
85
54
j
78
98
40
20
23
23
85
54
j
78
98
15
18
i
20
23
23
15
18
85
54
78
98
i
j
85 > 40, therefore stop incrementing i and start decrementing j
40
20
23
23
15
18
85
ij
54
78
98
18
85
j
i
18 < 40, therefore stop decrementing j.
54
78
98
20
23
23
15
Also notice that i has become greater than j. Hence, we swap a[j], i.e.,
18 with Pivot, i.e., 40 to achieve the first partition where all the
elements to the left of 40 are less than or equal to 40 and all the
elements to the right of 40 are greater than or equal to 40.
18
20
23
23
15
40
85
54
78
98
Pivot
---------- <=40 --------------------------- =>40 ---------
Similarly, sort the two subarrays 18 20 23 23 15 and 85 54 78 98
recursively until all the elements are sorted.
Analysis:
Input size: Number of elements in the array, n.
Basic operation: Key comparison operation A[i] >= p and A[i] <= p.
Let C(n) be the number of times the key comparison operation is
executed.
Best case:
It occurs when all the splits happen in the middle of the
corresponding subarrays.
For the split to happen in the middle of the array, n comparisons
are needed, and after which the array will be divided into two
equal subarrays.
Therefore,
C(n) = 0
= C(n/2) + C(n/2) + n
for n = 1
for n > 1
= 2 [ 2 C(2k-2) + 2k-1 ] + 2k
= 22 C(2k-2) + 2 * 2k
=
=
=
= 2i C(2k-i) + i * 2k
When i = k,
= 2k + k * 2k
= n + log2 n * n
C(n) (n log2 n)
Worst case:
It occurs when the splits happen in at the extremes.
For the split to happen at the extremes (n + 1) comparisons are
needed, and after which one of the two subarrays will be empty
while the size of the other will be just one less than the size of the
array being partitioned.
Therefore,
C(n) = 0
= C(n - 1) + (n + 1)
for n = 1
for n > 1
C(n) = C(n - 1) + (n + 1)
= [ C(n - 2) + n ] + (n + 1)
= C(n - 2) + n + (n + 1)
= [ C(n - 3) + (n 1) ] + n + (n + 1)
= C(n - 3) + (n 1) + n + (n + 1)
= ...
= ...
= ...
= C(n i) + (n i + 2) + ... + n + (n + 1)
when i = n 1,
= C(1) + (n (n 1) + 2 ) + ... + n + (n + 1)
= 3 + .. + n + (n + 1)
(n + 1)(n + 2)
= ---------------- - 3
2
2
C(n) (n )
Average case:
(n+1) comparisons are made before partitioning. Let k be
the position of the pivot element.
k
k-1 elements
n-k elements
.equation 1
k=1
.equation 3
.equation 4
K=1
C (n) = 1 + C (n / 2)
=1
for n > 1
for n = 1
Fig 4.2
Binary Tree
Ex. 1: Classic traversals (preorder, inorder, postorder)
All tree traversals visit nodes of binary tree recursively by visiting trees
root and its left and right subtree. They differ in just timing of roots visit.
Preorder Traversal: Root is visited before left and right subtree are
visited (Root Left Right).
Inorder Traversal: Root is visited after visiting its left subtree but
before visiting right subtree (Left Right Root).
Postorder Traversal: Root is visited after visiting right and left subtree
(Left Right Root).
Algorithm Inorder(T)
if T
Inorder(Tleft)
print(root of T)
Inorder(Tright)
Algorithm Preorder(T)
if T
print(root of T)
Preorder(Tleft)
Preorder(Tright)
Algorithm Postorder(T)
if T
Postorder(Tleft)
Postrder(Tright)
print(root of T)
Efficiency: (n)
Note: The analysis is same as the analysis for the algorithm to find the
height of a binary tree
Ex. 2: Computing the height of a binary tree
TL
TR
Algorithm Height(T)
//Computes recursively height of binary tree.
//Input:Binary tree T.
//Output:Height of T.
If T = 0
return 1 //Empty tree
else
return max{Height (Tl),Height(Tr)}+1.
Analysis:
Input size: Number of nodes in the tree, n.
Basic operation: Key comparison operation T = 0.
Let C(n) be the number of times the comparison operation is
performed.
The comparison operation T = 0 is performed once at each of the
internal nodes and twice at the leaf nodes.
To show that the comparison operation is performed twice at the
leaf nodes, the binary tree can be extended to form a extended
binary tree in which each of the leaf nodes of the binary tree have
two nodes called as external nodes which may be represented by
square boxes.
c00
c01
a00
a01
=
c10
c11
b00
b01
b10
b11
*
a10
a11
m1 + m4 - m5 + m7
m3 + m5
=
m2 + m4
where,
m1 = (a00 + a11) * (b00 + b11)
m2 = (a10 + a11) * b00
m3 = a00 * (b01 b11)
m4 = a11 * (b10 b00)
m5 = (a00 + a01) * b11
m6 = (a10 a00) * (b00 + b01)
m1 + m3 m2 + m6
Strassens
algorithm
makes
seven
multiplications
and
18
The same concept can be extended to multiply two n-by-n matrices A and
B by dividing them into four n/2-by-n/2 submatrices as shown in the
above formula
Apply the above formulas recursively to the submatrices obtained, until
the matrices reduce to order 2. When the matrices reduce to order 2, their
product can be easily found by using the formulas discussed above.
Strassens algorithm requires that the order of the matrices be an exact
power of 2and if they are not an exact power of 2, they can be padded
with zeros.
Analysis:
Input size: Order of the matrix, n.
Basic operation: Multiplication operation.
Let C (n) be the number of times multiplication operation is executed.
C (n) is given by the following recurrence:
C(n) = 7C (n/2)
if n >1
if n = 1
C(2k) = 7 * C(2k-1)
= 7 ( 7 * C(2k-2)) = 72 * C (2k-2)
= 73 * C(2k-3)
=
=
=
= 7i * C(2k-i)
When i = k,
= 7k * C(1)
= 7k
= 7 log2 n
= n log2 7 (because a logc b = b logc a)
= n 2.807
Step 2: Find recursively the closest pairs for the left and right subsets.
Step 3: Set d = min{d1, d2}
We can limit our attention to the points in the symmetric vertical strip
of width 2d as possible closest pair. Let C1 and C2 be the subsets of
points in the left subset S1 and of the right subset S2, respectively,
that lie in this vertical strip. The points in C1 and C2 are stored in
increasing
Analysis:
Input size: Number of points, n.
Basic operation: Finding the square in the expression d Sqrt ( ( xi
xj )2 + ( yi yj )2 ) .
Let C (n) be the number of times, square is found.
C (n) is given by the following recurrence:
C(n) = 2C (n/2) + cmerge (n)
In the worst case cmerge (n) O (n)
Therefore, By the Master Theorem (with a = 2, b = 2, d = 1)
C(n) O(n log n)
Convex-Hull Algorithm
Convex hull: smallest convex set that includes given points
Assume points are sorted by x-coordinate values
Identify extreme points P1 and P2 (leftmost and rightmost)
Compute upper hull recursively:
- Find point Pmax that is farthest away from line P1P2
- Compute the upper hull of the points to the left of line
P1Pmax
P2
Analysis:
Finding point farthest away from line P1P2 can be done in linear time
Time efficiency:
Worst case: (n2) (as quicksort)
Average case: (n) (under reasonable assumptions about
distribution of points given)
If points are not initially sorted by x-coordinate value, this can be
accomplished in O (n log n) time
Explanation:
Assume that the array A[on-2] is sorted giving us an array of size n-1.
Find an appropriate position for A[n-1] among the sorted elements and
insert it.
It can be done in three ways:
Scan the sorted subarray from left to right until the first element
greater than or equal to A[n-1] is encountered and then insert A[n-1]
before that element.
Straight insertion sort / Insertion sort: Scan the sorted subarray from
right to left until the first element less than or equal to A[n-1] is
encountered and then insert A[n-1] after that element.
Binary insertion sort: Use binary search to find an appropriate position
for A[n-1] in the sorted portion of the array.
Example:
Sort 6, 4, 1, 8, 5
6|4 1 8 5
4 6|1 8 5
1 4 6|8 5
1 4 6 8|5
1 4 5 6 8
Analysis:
Input size: Number of elements in the array, n.
Basic operation: Key comparison operation, A[j] > v.
Let C (n) be the number of times the key comparison operation is
executed.
Best case:
It occurs when the elements in the list are sorted.
n-1
C(n) = 1
i=1
= n 1 (n).
Worst case:
It occurs when the elements in the list are sorted in the reverse order.
n-1 i-1
C(n) =
i=1
j=0
n-1
= (i - 1) + 1
i=1
n-1
= i
i=1
= (n 1) + (n 2) + + 1 = n * (n 1) / 2
= (n2 n) / 2 (n2).
Average case
In average case C (n) (n2).
Depth-First Search
DFS Traversal:
It selects and visits a starting vertex v.
A vertex w adjacent to v and which is not visited earlier is explored,
leaving the rest of the vertices, which are adjacent to v unexplored.
When the vertex w is completely explored, the next vertex adjacent to v
is explored.
The above process is repeated until all the vertices are explored.
It visits the vertices of a graph recursively using a stack.
A vertex is pushed onto the stack when it is reached for the first time
A vertex is popped off the stack when it becomes a dead end, i.e.,
when there is no adjacent unvisited vertex
DFS Forest:
Solution
DFS tree:
abgcdh
abgcd
C(n) =
v=1
w=1
n
(n 1 + 1)
v=1
n
= n
v=1
= n (n 1 + 1)
C(n) n2
Analysis: Adjacency Linked List
Input size: Number of vertices V and edges E
Basic Operation: Comparison operation If w is marked with 0.
Let C(n) be the number of times the comparison operation is executed.
Scanning the list of vertices v in V (V).
The number of times the comparison operation is performed depends
on the recursive call dfs(w) which is proportional to the number of
edges and it (E)
C(n) = (V + E)
Applications of DFS:
Checking connectivity, finding connected components.
Checking acyclicity.
Searching state-space of problems for solution.
Breadth-First Search
BFS Traversal:
Select and visit a starting vertex v
Visit all the vertices that are adjacent to v then all unvisited vertices two
edges apart from v and so on until all the vertices are visited.
It visits the vertices of a graph using a Queue.
A vertex is queued when it is reached for the first time.
A vertex is removed from the queue when it when all the vertices
adjacent to it are visited.
BFS Forest:
It is constructed from the breadth first search traversal of a graph.
The traversals starting vertex serves as the root of the first tree in such a
forest.
Whenever a new unvisited vertex is reached for the first time, it is
attached as a child to the vertex it is being reached from with an edge
called a tree edge.
If the graph has an edge leading to a previously visited vertex other than
its immediate predecessor, it is called a cross edge.
Solution
BFS tree:
C(n) =
v=1
w=1
n
(n 1 + 1)
v=1
n
= n
v=1
= n (n 1 + 1)
C(n) n2
Analysis: Adjacency Linked List
Input size: Number of vertices V and edges E
Basic Operation: Comparison operation If w is marked with 0.
Let C(n) be the number of times the comparison operation is executed.
Scanning the list of vertices v in V (V).
The number of times the comparison operation is performed depends
on the recursive call dfs(w) which is proportional to the number of
edges and it (E)
C(n) = (V + E)
Applications of BFS:
To find paths from a vertex to all other vertices with the smallest number
of edges
Connectivity
Acyclicity
DAG
Topological sorting Algorithms
1. DFS-based algorithm:
2. Source removal algorithm
Not a DAG
Perform DFS traversal, noting the order in which the vertices are popped
off the stack.
Reverse the order of the vertices obtained in the above step.
Example:
Example:
Topological order is : a, b, e, f, c, d, g, h
Note: While selecting a node for deletion, any node, which doesnt have an
incoming edge, can be selected. The above sequence is just one such order.
There can be other topological orderings of the vertices also, depending on
which node we select for deletion.
Efficiency: The same as that of DFS-based algorithm
Instance
simplification:
Transforms
problem
to
Another representation /
Solution
Analysis:
Efficiency of the entire presorting algorithm is:
C(n) = Csort(n) + Cscan(n)
(nlog n) + (n)
= (nlog n)
Better than the brute force algorithms which belongs to (n2)
Analysis:
Efficiency of the entire presorting algorithm is:
C(n) = Csort(n) + Cscan(n)
(nlog n) + (n)
= (nlog n)
Better than the brute force algorithms which belongs to (n2)
return p
Example:
Evaluate p(x) = 2x4 - x3 + 3x2 + x - 5
= x (2x3 x2 + 3x + 1) - 5
= x (x (2x2 - x + 3) + 1) - 5
= x (x (x (2x - 1) + 3) + 1) - 5
Substitution into the last formula leads to a faster algorithm
Same sequences of computations are obtained by simply arranging the
coefficient in a table and proceeding as follows:
-------------------------------------------------------------------------------------------Coefficients: 2
-1
3
1
-5
-------------------------------------------------------------------------------------------x=3
2 3*2+(-1)=5 3*5+3=18 3*18+1=55 3*55+(-5)=160
--------------------------------------------------------------------------------------------
Analysis:
Input size: Degree of the polynomial, n.
Basic operation: Multiplication and addition operation.
Let C (n) be the number of times the multiplication and addition
operations are performed
n-1
C (n) =
= n 1 + 1 = n (n)
i=0
1
12*a=a
-------------------------------------------------------------------------------------------(Computed left-to-right)
Explanation:
Scan ns binary expansion from right to left and compute an as the
product of terms a2i corresponding to 1s in this expansion.
Example: Compute a13 by the right-to-left binary exponentiation.
Here, n = 13 = 11012
-------------------------------------------------------------------------------------------1
Binary rep. of 13
a8
a4
a2
a2i terms
product accumulator
a5 *a8= a13
a*a4= a5
-------------------------------------------------------------------------------------------(Computed right-to-left)
Example:
Array A[0..5]
62 31 84 96 19
47
Initially
count []
After pass i = 0
count []
After pass i = 1
After pass i = 2
count []
count []
After pass i = 3
After pass i = 4
count []
count []
Final state
Array A[0..5]
count []
19 31 47 62 84
Analysis:
Input size: Number of elements in the array, n.
96
Distribution counting
If element values are integers between some lower bound l and upper
bound u, stored in an array A, then the frequency of each of those
values can be computed and stored them in an array F [0..u - l].
The elements of A whose values are equal to the lowest possible value
l are copied into the first F [0] elements of another array S, i.e.,
positions 0 through F[0] 1, the elements of value l + 1 are copied to
positions from F[0] to (F[0] + F[1]) 1, and so on.
Since each accumulated sums of frequencies are called a distribution
in statistics, the method is known as distribution counting.
ALGORITHM: DistributionCounting(A[0,,n 1])
// Sorts an array of integers from a limited range by distribution counting
// Input: Array A[0..n 1] of integers between l and u (l u)
// Output: Array S[0..n 1] of As elements sorted in nondecreasing order
for j 0 to u l do D[j] 0
for i 0 to n 1 do D[A[i] - l] D[A[i] - l] + 1
for j 1 to u l do D[j] D[j 1] + D[j]
for i n 1 downto 0 do
j A[i] l
S[D[j] 1] A[i]
D[j] D[j] 1
return S
Example:
13 11 12 13 12
Array A[0..5]
Array values
Frequencies
Distribution values
11
1
1
D [0..2]
A[5] = 12
A[4] = 12
A[3] = 13
A[2] = 12
A[1] = 11
A[0] = 13
12
3
4
12
13
2
6
S [0..5]
12
12
13
12
11
13
Analysis:
It is linear because it makes just two consecutive passes through its
input array A.
AAOAAB
Case 4: if c happens to be the last character in the pattern and there
are other cs among its first m 1 characters, align the rightmost
occurrence of c among the first m 1 characters in the pattern with
the texts c.
............B................
BAOBAB
BAOBAB
Shift sizes can be precomputed by the formula:
Distance from cs rightmost occurrence in pattern
among its first m-1 characters to its right end
t(c) =
Patterns length m, otherwise
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
1 2 6 6 6 6 6 6 6 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6
_
6
BAOBAB
Search result: unsuccessful search
BARD LOVED BANANAS
BANANA
BANANA
BANANA
Search result: successful search
kk+1
if k = m
return i m + 1
else
i i + Table [T[i]]
return -1
Boyer-Moore Algorithm
Based on the same two ideas:
Comparing pattern characters to text from right to left
precomputing shift sizes in two tables
bad-symbol table indicates how much to shift based on texts
character causing a mismatch
good-suffix table indicates how much to shift based on matched
part (suffix) of the pattern (taking advantage of the periodic
structure of the pattern)
suffix
with
corresponding
prefix;
Boyer-Moore Algorithm
After matching successfully 0 < k < m characters, the algorithm shifts the
pattern right by
d = max {d1, d2}
where, d1 = max{t(c) - k, 1} is bad-symbol shift
d2(k) is good-suffix shift
Step 1: Fill in the bad-symbol shift table
Step 2: Fill in the good-suffix shift table
Step 3: Align the pattern against the beginning of the text
Step 4: Repeat until a matching substring is found or text ends:
Compare the corresponding characters right to left.
If no characters match, retrieve entry t1(c) from the bad-symbol table
for the texts character c causing the mismatch and shift the pattern to
the right by t1(c). If 0 < k < m characters are matched, retrieve entry
t1(c) from the bad-symbol table for the texts character c causing the
mismatch and entry d2(k) from the good-suffix table and shift the
pattern to the right by
d=max{d1,d2}
where d1 = max{t1(c) - k, 1}.
Example:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
1 2 6 6 6 6 6 6 6 6 6 6 6 6 3 6 6 6 6 6 6 6 6 6 6 6
BESS_KNEW_ABOUT_BAOBABS
BAOBAB
d1 = t(K) = 6 B A O B A B
d1 = t(_)-2 = 4
d2(2) = 5
BAOBAB
d1 = t(_)-1 = 5
d2(1) = 2
B A O B A B (success)
k pattern
d2
1 BAOBAB 2
2 BAOBAB 5
3 BAOBAB 5
4 BAOBAB 5
5 BAOBAB 5
_
6
8. Dynamic Programming
Dynamic Programming is a general algorithm design technique for solving
problems defined by or formulated as recurrences with overlapping
subinstances
Some of the recursive algorithms solve common sub problems more
than once. Rather than solving the overlapping subproblems again and
again, dynamic programming supports solving each of the smaller
subproblems only once and recording the results in a table from which
the solution to the original problem can be obtained.
Dynamic programming, like divide-and-conquer method, solves
problems by combining solutions to sub problems.
In divide and conquer we partition the problem into independent
subproblems, solve the subproblems recursively and then combine
their solutions to solve the original problem.
In contrast, dynamic programming is applicable when subproblems
are not independent, that is when subproblems share subproblems.
Divide and conquer method does more work, by repeatedly solving
the common subproblems.
Dynamic programming algorithm solves every sub problem just once
and then saves the answer in a table there by avoiding the work of
recomputing answer every time the subproblem is encountered.
Dynamic programming is applied to optimization problems.
for n 0
0 0
0 1
1 1
.
.
.
n-1
n
. . .
k-1
C(n-1,k-1)
No. of
elements
Example: C (9, 5)
0
0
1
2
3
4
5
6
7
8
9
0
1
1
1
1
1
1
1
1
1
1
Analysis:
No. of combinations
1
2
1
3
3 1
4
6 4
5
10 10
6
15 20
7
21 35
8
28 56
9
36 84
C (9, 5) = 126
1
5
15
35
70
126
1
6
21
56
126
C(n-1,k)
C(n,k)
Explanation:
It constructs the transitive closure, R(n), through a series of n-by-n
boolean matrices, R(0), , R(k-1), R(k), R(n)
All the elements of each matrix R(k) can be computed from its
immediate predecessor R(k-1).
The elements of rij (k) in the ith row and jth column of matrix R(k)
(k = 0,1,2..n) is equal to 1 if and only if there exists a directed
path from the ith vertex to the jth vertex with each intermediate vertex,
if any, numbered not higher than k.
The formula for generating the elements of matrix R(k) from the
elements of the matrix R(k-1)
rij (k) = rij (k-1) or rik (k-1) and rkj (k-1)
Example:
a
Adjacency matrix
a
b
c
d
a
A= b
c
d
0
0
0
1
1
0
0
0
0
0
0
1
0
1
0
0
0
R =A= 0
0
1
1
0
0
0
0
0
0
1
0
1
0
0
0
0
0
1
1
0
0
1
0
0
0
1
0
1
0
0
0
0
0
1
1
0
0
1
0
0
0
1
1
1
0
1
0
0
0
1
1
0
0
1
0
0
0
1
1
1
0
1
1
1
0
1
1
1
0
1
1
1
0
1
1
1
0
1
(0)
(1)
R =
(2)
R =
(3)
R =
(4)
R =
Analysis:
Input size: order of the matrix, n.
Basic operation: R(k) [i,j] = R (k-1)[i,j] or R (k-1) [i,j] and R(k-1)[k,j]
Let C (n) be the number of times the above operation is performed.
n
C(n) =
k=1
i=1
n
1
j=1
n
=
k=1
n
(n-1+1)
i=1
n
=
k=1
n
n
i=1
n
= n (n-1+1)
k=1
C(n) (n3)
All the elements of each matrix D(k) can be computed from its
immediate predecessor D(k-1).
The formula for generating the elements of matrix D(k) from the
elements of the matrix D(k-1)
dij (k) = min {dij (k-1), dik (k-1) + d kj (k-1)} for k >=1, dij (0) = wij
Example:
10
a
b
40
20
50
c
Cost matrix
b
c
a
W=b
c
d
0
999
50
999
10
0
999
999
10
0
999
999
999
999
0
60
40
20
999
0
60
(0)
D =W=
Computing D(1)
0
999
50
999
999
999
0
60
40
20
999
0
From a
A(a,a)=min{A(a,a),A(a,a)+A(a,a)}=0
A(a,b)=min{A(a,b),A(a,a)+A(a,b)}=10
A(a,c)=min{A(a,c),A(a,a)+A(a,c)}=999
A(a,d)=min{A(a,d),A(a,a)+A(a,d)}=40
From b
A(b,a)=min{A(b,a),A(b,a)+A(a,a)}=999
A(b,b)=min{A(b,b),A(b,a)+A(a,b)}=0
A(b,c)=min{A(b,c),A(b,a)+A(a,c)}=999
A(b,d)=min{A(b,d),A(b,a)+A(a,d)}=20
From c
A(c,a)=min{A(c,a),A(c,a)+A(a,a)}=50
A(c,b)=min{A(c,b),A(c,a)+A(a,b)}=60
A(c,c)=min{A(c,c),A(c,a)+A(a,c)}=0
A(c,d)=min{A(c,d),A(c,a)+A(a,d)}=90
From d
A(d,a)=min{A(d,a),A(d,a)+A(a,a)}=110
A(d,b)=min{A(d,b),A(d,a)+A(a,b)}=999
A(d,c)=min{A(d,c),A(d,a)+A(a,c)}=60
A(d,d)=min{A(d,d),A(d,a)+A(a,d)}=0
0
10 999 40
D = 999 0
999 20
50 60 0
90
110 999 60 0
Similarly the following matrices are computed
(1)
(2)
D =
0
999
50
110
0
10
0
60
999
10
999
999
0
60
999
30
20
80
0
30
D(3) =
130 0
999 20
50 60 0
80
110 120 60 0
0
130
50
110
(4)
D =
10
0
60
120
90
80
0
60
30
20
80
0
Analysis:
Input size: order of the matrix, n.
Basic operation: dij (k) = min{dij (k-1), dik (k-1) + d kj (k-1)}
Let C (n) be the number of times the above operation is performed.
n
C(n) =
k=1
i=1
n
1
j=1
n
=
k=1
n
(n-1+1)
i=1
n
=
k=1
n
n
i=1
n
= n (n-1+1)
k=1
C(n) (n3)
C
B
Optimal
BST for
a i , ..., a
k-1
Optimal
BST for
a k +1 , ..., a
k-1
C[i,j] = min {pk 1 + ps (level as in T[i,k-1] +1) +
ikj
s=i
j
ps (level as in T[k+1,j] +1)}
s =k+1
After simplifications, we obtain the recurrence for C[i,j] :
C[i,j] = min {C[i,k-1] + C[k+1,j]} + ps for 1 i j n
C[i,i] = pi
for 1 i j n
0
p1
0
n
goal
p2
C[i,j]
pn
n+1
Example:
key
A B C D
probability 0.1 0.2 0.4 0.3
The tables below are filled diagonal by diagonal: the left one is filled using
the recurrence
j
C[i,j] = min {C[i,k-1] + C[k+1,j]} + ps , C[i,i] = pi ;
ikj
s=i
the right one, for trees roots, records ks values giving the minima
Analysis:
Time efficiency: (n3) but can be reduced to (n2) by taking
advantage of monotonicity of entries in the
root table, i.e., R[i,j] is always in the range
between R[i,j-1] and R[i+1,j]
Space efficiency: (n2)
if j wi < 0
j wi
i1 0
wi, vi
n 0
V [i 1, j wi]
V [i 1, j]
V [i, j]
goal
The goal is to find V [n, W], the maximal value of a subset of the
given items that fit into the knapsack of capacity W, and an optimal
subset itself.
Example:
Item
weight
value
Rs. 12
Rs. 10
Rs. 20
Rs. 15
Capacity W = 5
V [1, 1]:
j wi = 1 2 which is < 0.
V [1, 1] = V [i - 1, j] = V [1 - 1, 1] = 0
V [1, 2]:
j wi = 2 2 which is = 0,
V [1, 2] = max{V [i 1, j], vi + V [i 1, j wi]}
= max{V [1 - 1, 2], 12 + V [1 1, 2 2]}=max {0, 12 + 0}
= 12
V [1, 3]:
3 2 > 0,
V [1, 3] = max{V [1 - 1, 3], 12 + V [1 1, 3 2]}=max {0, 12 + 0}
= 12
V [2, 1]:
11=0
V [2, 1] = max{V [2 - 1, 1], 10 + V [2 1, 1 1]}=max {0, 10 + 0}
= 10
V [2, 2]:
21>0
V [2, 2] = max{V [2 - 1, 2], 10 + V [2 1, 2 1]}
= max {12, 10 + 0}
= 12
V [2, 3]:
31>0
V [2, 3] = max{V [2 - 1, 3], 10 + V [2 1, 3 1]}
= max {12, 10 + 12} = 22
The rest of the table entries can be filled similarly. The completely
filled table is as shown below:
Capacity j
i
w1 = 2, v1 = 12
12
12
12
12
w2 = 1, v2 = 10
10
12
22
22
22
w3 = 3, v3 = 20
10
12
22
30
32
w4 = 2, v4 = 15
10
15
25
30
37
The top down approach solves the common subproblems more than
once and hence it is very inefficient.
Even though the bottom up approach solves common subproblems
only once, it solves all the subproblems but some of these smaller
subproblems are often not necessary for getting a solution
Memory functions combine the strengths of the top down and bottom
up approach and solve only subproblems that are necessary only
once.
Initially all the table entries are initialized with a special Null symbol
to indicate that they have not yet been calculated by a technique
called virtual initialization and recursive function is called with the
values i = n and j = w.
The idea of memory functions is implemented in the following
algorithm.
w1 = 2, v1 = 12
12
12
12
w2 = 1, v2 = 10
12
22
22
w3 = 3, v3 = 20
22
32
w4 = 2, v4 = 15
37
9. Greedy Technique
Greedy technique suggests constructing a solution to a sequence of
steps each expanding a partially constructed solution obtained so far
until a complete solution to the problem is reached.
It constructs a solution to an optimization problem piece by piece
through a sequence of choices that are:
Feasible, i.e. satisfying the constraints
Locally optimal (with respect to some neighborhood
definition)
Greedy (in terms of some measure), and irrevocable
c
a
Find a minimum weight edge e = (v, u) among all the edges (v, u)
such that v is in VT and u is in V - VT
VT VT { u}
ET ET { e}
return ET
Example: Consider the graph given below
Distance Matrix:
D(1) = 0
D(2) = 5
D(3) = 10
D(4) =
0
5
10
15
1
0
5
10
2
3
4
5
10
0
15
0
15 0
30 35
20 25 45
30
35
0
40
20
25
45
40
0
Near Matrix:
0
5
10
15
N(1) = 1
N(2) = 1
N(3) = 1
N(4) = 1
1
1
1
2
1
1
1
2
D(5) =
D(6) =
30
20
30
20
N(5) = 1
N(6) = 1
2
2
2
2
On each iteration, add the next edge on the sorted list only if it
would not create a cycle, if it would, skip the edge.
Some of the subset operations necessary for kruskals algorithm
are:
Makeset (x): It creates one element set
Find (x): Returns the representative of the subset containing
x
Union (x, y): It constructs the union of the disjoint subsets
Sx and Sy containing x and y respectively and adds it to the
collection to replace Sx and Sy
Implementation of disjoint subsets:
a) Quick Find:
It uses an array Arr, indexed by the elements of the
underlying set S
The arrays values indicates the subsets representative
containing those elements
Each subset is implemented as a linked list whose header
contains pointer to the first and last elements of the list along
with the number of elements in the list.
Makeset ():
o Assign the corresponding element in the representative
array to x i.e., Arr[i] = i.
o (n)
Find (x):
o Retrieve the xs representative in the representative array
i.e., return Arr[x].
o (1)
Union (x, y):
o Implemented by replacing all the entries of the array Arr
where x is present with y or vice versa.
o O(n)
b) Quick Union:
Represent each subset by a rooted tree.
The nodes of the tree contain the subsets elements with the
roots element considered the subsets representative.
The trees edges are directed from children to their parents.
Makeset (x):
o It requires the creation of a single node tree.
o (n)
Find (x):
o Performed by following the pointer chain from the node
containing x to the trees root whose element is returned
as the subsets representative
o (n)
Union (x, y):
o Implemented by attaching the root of the ys tree to the
root of the xs tree
o (1)
Algorithm: Kruskal(G)
ET Null
ecounter 0
k0
Algorithm: Dijkstra(G, s)
Initialize(Q)
for every vertex v in V do
dv
Insert(Q, v, dv)
ds 0
Decrease(Q, s, ds)
VT Null
For I 0 to |V| - 1 do
u DeleteMin(Q)
VT VT { u}
For every vertex u in V - VT that is adjacent to u do
If du + w(u, u) < du
du du + w(u, u)
pu u
Decrease(Q, u, du)
Analysis:
O(|V|2) for graphs represented by weight matrix and array
implementation of priority queue.
O(|E|log|V|) for graphs represented by adj. lists and min-heap
implementation of priority queue.
Huffmans algorithms:
Initialize n one-node trees with alphabet characters and the tree
weights with their frequencies.
Repeat the following step n-1 times: join two binary trees with
smallest weights into one (as left and right subtrees) and make its
weight equal the sum of the weights of the two trees.
Mark edges leading to left and right subtrees with 0s and 1s,
respectively.
Example:
Consider 5 character analphabet {A, B, C, D, _} with following occurrence probability.
------------------------------------------------------------
Character
Probability:
0.35 0.1
0.2
0.2
0.15
-------------------------------------------------------------
0.2
0.2
0.15
Code word 11
00
01
101
100
-----------------------------------------------------------With occurrence probability given and code word length obtained, expected
number of bits per character in this code is
2 * 0.35 + 3 * 0.1 + 2 * 0.2 + 2 * 0.2 + 3 * 0.15 = 2.25
Analysis:
The list of characters can be implemented as a min-heap.
For loop is executed exactly n -1 times and since each heap operation
requires time O(log n) loop contributes O(nlog n) to the running time.
Thus total running time of Huffman on a set of n characters is O(n
log n).
Problem
Lower bound
Tightness
Sorting (comparison-based)
(nlog n)
yes
(log n)
yes
Element uniqueness
(nlog n)
yes
(n)
unknown
(n2)
unknown
If there is a gap between the efficiency of the fastest algorithm and the
best lower bound known, there is roo m for possible improvement :
either a faster algorithm matching the lower bound could exist or a
better lower bound could be proved.
If the lower bound is already tight, we can hope for a constant-factor
improve ment at best.
Methods for establishing lower bounds
1. Trivial Lower Bounds
2. Information-Theoretic Arguments
3. Adversary Arguments
4. Proble m Reduction
Information-Theoretic Arguments
It is called information-theoretic argument because of its connection
to information theory.
It has proved to be quite useful for finding the so-called informationtheoretic lower bounds for many problems involving comparisons.
Its underlying idea can be realized much more precisely through the
mechanism of decision trees.
Adversary Arguments
E.g.: Merging two sorted lists of size n into a single list of size 2n.
a1 < a2 < < an and b1 < b2 < < bn
o To derive the lower bound, the adversary will employ the
Problem Reduction
The table below lists several important problems that are often used
for this purpose.
Problem
Lower bound
Tightness
Sorting (comparison-based)
(nlog n)
yes
(log n)
yes
Element uniqueness
(nlog n)
yes
(n)
unknown
(n2)
unknown
Since final results about complexity of many problems are not known,
the reduction technique is often used to compare the relative
complexity of problems.
E.g.: The formulas
x . y = ((x + y)2 (x - y)2) / 4
and
x2 = x . x
yes
no
a<b
no
yes
a< c
no
b<c
Note that the number of leaves will be at least as large as the number
of possible outcomes.
The algorithms work on a particular input of size n can be traced by a
path from the root to a leaf in its decision tree.
The number of comparisons made by the algorithm on any run is
equal to the number of edges in that path and hence, the number of
comparisons in the worst case is equal to the height of the algorithms
decision tree.
It can be proved that for any binary tree with l leaves and height h,
h log 2 l
which puts a lower bound on the heights of binary decision trees and
hence the worst-case number of comparisons made by any
comparison-based algorithm.
a<b
no
abc
yes
bac
no
b< c
yes
acb
a<b<c
yes
a<c
a<c<b
no
a<c
bca
b<a<c
no
c<a<b
yes
b<c
b<c<a
no
c<b<a
Class P (Polynomial)
Class P is a class of decision problems that can be solved in
polynomial time by (deterministic) algorithms. E.g.: searching,
element uniqueness, graph connectivity etc.
Problems for which neither a polynomial-time algorithm has been
found, nor has the impossibility of such an algorithm been proved.
o Hamiltonian circuit
o Traveling sales
o Knapsack
o Graph coloring etc.
Nondeterministic algorithm
It is a two-stage procedure that takes as it input an instance I of a
decision problem and does the following
o Nondeterministic (guessing) stage: An arbitrary string S is
generated that can be thought of as a candidate solution to the
given instance I.
o Deterministic (verification) stage: A deterministic algorithm
takes both I and S as its input and outputs yes if S represents a
solution to instance I.
A nondeterministic algorithm is said to be nondeterministic
polynomial if the time efficiency of its verification stage is
polynomial.
Certain problems like the halting problem, is among the rare examples
of decision problems that are known not to be in NP, which leads to
the most important open question of theoretical computer science: Is P
a proper subset of NP, or are these two classes, in fact, the same?
P =? NP.
NP-complete problems
A decision problem D1 is said to be polynomially reducible to a
decision problem D2 if there exists a function t that transforms
instances of D1 to instances of D2 such that
o t maps all yes instances of D1 to yes instances of D2 and all no
instances of D1 to no instances of D2;
o t is computable by a polynomial-time algorithm.
A decision problem D is said to be NP-complete as shown in the
figure below if
o It belongs to class NP;
o Every problem in NP is polynomially reducible to D.
NP problems
NP -complete
problem
known
NP-complete
problem
candidate
for NP completeness
P = NP would imply that every problem in NP, including all NPcomplete proble ms, could be solved in polyno mial time.
If a polyno mial-time algorithm for just one NP-co mplete proble m is
discovered, then every problem in NP can be solved in polyno mial
time, i.e. P = NP.
Most but not all researchers believe that P NP, i.e., P is a proper
subset of NP. But Levin contended that we should expect the P = NP
outcome.
11 Backtracking
It is a more intelligent variation of the exhaustive search technique.
The principal idea is to construct solutions one component at a time
and evaluate such partially constructed candidates as follows:
If a partially constructed solution can be developed further
without violating the problems constraints, it is done by taking
the first remaining legitimate option for the next component.
If there is no legitimate option for the next component, no
alternatives for any remaining component need to be
considered and the algorithm backtracks to replace the last
component of the partially constructed solution with its next
option.
Constructs a tree of choices being made called as the state-space tree
in which
Nodes represent partial solutions and
Edges represent choices in extending partial solutions
Fig 11.1
Fig 11.2
8-Queens Problem
Place 8 queens on an 8-by-8 chess board so that no two queens attack
each other are shown in Fig 11.3.
A solution requires that no two queens share the same row, column, or
diagonal.
The solution to the 8-Queens problem where n = 8 is:
Divide n by 12. Remember the remainder (n is 8 for the eight
queens puzzle).
Write a list of the even numbers from 2 to n in order.
If the remainder is 3 or 9, move 2 to the end of the list.
Append the odd numbers from 1 to n in order, but, if the remainder
is 8, switch pairs (i.e. 3, 1, 7, 5, 11, 9, )
If the remainder is 2, switch the places of 1 and 3, then move 5 to
the end of the list.
If the remainder is 3 or 9, move 1 and 3 to the end of the list.
Place the first-column queen in the row with the first number in the
list, place the second-column queen in the row with the second
number in the list, etc.
Fig 11.3
Fig 11.4
Assuming the staring vertex as a, make vertex a the root of the statespace tree.
The first component of the solution is a first intermediate vertex of a
Hamiltonian cycle to be constructed, which is b in this case (using
alphabet order to break tie).
From b, the algorithm proceeds to c, then to d, then to e, and finally to
f, which proves to be a dead end.
So, the algorithm backtracks from f to e, then to d, and then to c,
which provides the first alternative for the algorithm to pursue.
Going from c to e eventually proves useless, and the algorithm has to
backtrack from e to c and then to b.
From there, it goes to the vertices f, e, c, and d, from which it can
legitimately return to a, yielding the Hamiltonian circuit a, b, f, e, c, d,
a.
The state-space tree is shown below in Fig 11.5
To find another solution, the above process can be continued by
backtracking from the leaf of the solution found.
Fig 11.5
node.
If s is equal to d, we have a solution to the problem.
If s is not equal to d, we can terminate the node as
Fig 1
The value of the nodes bound is not better than the value of the
best solution seen so far.
Example:
Assign four people (a, b, c, d) to four jobs (1, 2, 3, 4)
The cost of assigning a person to a particular job is given by the cost
adjacency matrix below:
Lower bound can be set by considering the fact that the cost of any
solution cannot be smaller than the sum of the smallest elements in
each of the matrixs rows, i.e. lb = 2 + 3 + 1 + 4 = 10.
Start with the root that corresponds to no elements selected from the
cost matrix with a lower bound, lb = 10.
Considering each one of the elements of the first row as being
selected, the first nodes of the first level of the tree are generated as
follows:
If the first element in the first row (9) is selected, then the
smaller elements in the other three rows (row2 - 3, row3 -1,
row4 - 4) lead to a lower bound of 9 + 3 + 1 + 4 = 17.
If the second element in the first row (2) is selected, then the
smaller elements in the other three rows (row2 - 3, row3 -1,
row4 - 4) lead to a lower bound of 2 + 3 + 1 + 4 = 10.
If the third element in the first row (7) is selected, then 3 in the
second row and 1 in the third row cannot be selected because a
Fig 12.1
Among the four live nodes, node 2 is the most promising node,
because it has the smallest lower-bound value.
Following the best-first search strategy, branch out from node 2 to
generate the second level of the nodes as follows, assuming the
second element of the first row (2) as already being selected:
If the first element in the second row (6) is selected, then the
smaller elements in the other three rows (row3 -1, row4 - 4)
lead to a lower bound of 2 + 6 + 1 + 4 = 13.
Second element in the second row cannot be selected because
an element in the same column is already selected (2 in row1).
If the third element in the second row (3) is selected, then 1 in
the third row cannot be selected because a selection in the same
column is already made. Hence selecting the next smaller
elements (row3 -5, row4 - 4) lead to a lower bound of 2 + 3 + 5
+ 4 = 14.
If the fourth element in the second row (7) is selected, then 4
and 6 in the fourth row cannot be selected because a selection in
the same columns is already made. Hence selecting the next
smaller elements (row3 -1, row4 - 6) lead to a lower bound of 2
+ 7 + 1 + 7 = 17.
The state-space tree with the first two levels consisting six live nodes
(1, 3, 4, 5, 6, 7) is as shown in the Fig 12.2
Fig 12.2
Among the six live nodes, node 5 is the most promising node.
Branching out from node 5 to generate the third level of the nodes as
follows, assuming the second element of the first row (2) and first
element of the second row as already being selected:
First element in the third row cannot be selected because an
element in the same column is already selected (6 in row2).
Second element in the third row cannot be selected because an
element in the same column is already selected (2 in row1).
If the third element in the third row (1) is selected, then
selecting 4 from row4 will lead to a lower bound of 2 + 6 + 1 +
4 = 13.
If the fourth element in the third row (8) is selected, then 4 in
the fourth row cannot be selected. 7 and 6 also cannot be
selected. Hence selecting 9 from row4 will lead to a lower
bound of 2 + 6 + 8 + 9 = 25.
The state-space tree with the third level of nodes is as shown in the
Fig 12.3
Fig 12.3
Inspecting the leave of the state-space tree reveals that leaf 8 with a
minimum cost of 13 represents the value of the best selection.
Example:
Consider a knapsack with capacity 10.
item
weight
value
v/w
-------------------------------------------1
4
Rs.40
10
2
7
Rs.42
6
3
5
Rs.25
5
4
3
Rs.12
4
The state-space tree is as shown in the Fig 12.4
Fig 12.4
w=0
v =0
ub = 0 + (10 0) (40 / 4) = 100.
The left child of the root, node 1, represents the subsets that
include item 1, with:
w=4
v = 40
ub = 40 + (10 4) (42 / 7) = 76.
The right child of the root, node 2, represents the subsets that
do not include item 1, with:
w=0
v=0
ub = 0 + (10 0) (42 / 7) = 60.
Since node 1 has a large upper bound than the upper bound of
node 2, it is more promising and we branch from node 1 first.
Node 3 represents the subsets that include item 2, but the total
weight of every subset represented by node 3 exceeds the
knapsacks capacity; hence node 3 can be terminated
immediately.
Node 4 represents the subsets that do not include item 2, with:
w=4
v = 40
ub = 40 + (10 4) (25 / 5) = 70.
Branch out from node 4, because it has a better upper bound
than node 2.
Node 5 represents the subsets that not include item 3, with:
w=9
v = 65
ub = 65 + (10 9) (12 / 3) = 69.
Node 6 represents the subsets that do not include item 3, with:
w=4
v = 40
ub = 40 + (10 4) (12 / 3) = 64.
Branch out from node 5, because it has a better upper bound
than node 6.
Node 7 represents the subsets that include item 4, but the total
weight of every subset represented by node 7 exceeds the
knapsacks capacity; hence node 7 can be terminated
immediately.
Node 8 represents the subsets that do not include item 4, with:
w=9
v = 65
ub = 65 + (10 9) (0 / 0) = 65.
Among the live nodes 2, 6 and 8, nodes 2 and 6 have smaller
upper-bound values than the value of node 8. Hence both can be
terminated making the subset {1, 3} of node 8 with value 65 the
optimal solution to the problem.
Fig 12.5
For any subset of tours that must include particular edges of a given
graph, the lower bound can be modified accordingly. E.g.: For all the
Hamiltonian circuits of the graph that must include edge (a, d), the
lower bound can be computed as follows:
lb = [(1 + 5) + (3 + 6) + (1 + 2) + (3 + 5) + (2 + 3)] / 2 = 16.
Applying the branch-and-bound algorithm, with the bounding
function lb = s / 2, to find the shortest Hamiltonian circuit for the
given graph, we obtain the state-space tree as shown below:
To reduce the amount of potential work, we take advantage of the
following two observations:
We can consider only tours that start with a.
Since the graph is undirected, we can generate only tours in
which b is visited before c.
In addition, after visiting n 1 cities, a tour has no choice but to visit
the remaining unvisited city and return to the starting one is shown in
the Fig 12.6
Fig 12.6
Root node includes only the starting vertex a with a lower
bound of
lb = [(1 + 3) + (3 + 6) + (1 + 2) + (3 + 4) + (2 + 3)] / 2 = 14.
Node 1 represents the inclusion of edge (a, b)
lb = [(1 + 3) + (3 + 6) + (1 + 2) + (3 + 4) + (2 + 3)] / 2 = 14.
Node 2 represents the inclusion of edge (a, c). Since b is not
visited before c, this node is terminated.
Node 3 represents the inclusion of edge (a, d)
lb = [(1 + 5) + (3 + 6) + (1 + 2) + (3 + 5) + (2 + 3)] / 2 = 16.
Node 1 represents the inclusion of edge (a, e)
lb = [(1 + 8) + (3 + 6) + (1 + 2) + (3 + 4) + (2 + 8)] / 2 = 19.
Among all the four live nodes of the root, node 1 has a better
lower bound. Hence we branch from node 1.
Node 5 represents the inclusion of edge (b, c)
lb = [(1 + 3) + (3 + 6) + (1 + 6) + (3 + 4) + (2 + 3)] / 2 = 16.
Node 6 represents the inclusion of edge (b, d)
lb = [(1 + 3) + (3 + 7) + (1 + 2) + (3 + 7) + (2 + 3)] / 2 = 16.
Node 7 represents the inclusion of edge (b, e)
lb = [(1 + 3) + (3 + 9) + (1 + 2) + (3 + 4) + (2 + 9)] / 2 = 19.
Since nodes 5 and 6 both have the same lower bound, we
branch out from each of them.
Node 8 represents the inclusion of the edges (c, d), (d, e) and
(e, a). Hence, the length of the tour,
l = 3 + 6 + 4 + 3 + 8 = 24.
Node 9 represents the inclusion of the edges (c, e), (e, d) and
(d, a). Hence, the length of the tour,
l = 3 + 6 + 2 + 3 + 5 = 19.
Node 10 represents the inclusion of the edges (d, c), (c, e) and
(e, a). Hence, the length of the tour,
l = 3 + 7 + 4 + 2 + 8 = 24.
Node 11 represents the inclusion of the edges (d, e), (e, c) and
(c, a). Hence, the length of the tour,
l = 3 + 7 + 3 + 2 + 1 = 16.
Node 11 represents an optimal tour since its tour length is better
than or equal to the other live nodes, 8, 9, 10, 3 and 4.
The optimal tour is a b d e c a with a tour length
of 16.
Example:
Consider the graph given in the Fig 13.1 below:
Fig 13.1
With a as the starting vertex, the nearest-neighbor algorithm yields
the tour sa: a b c d a of length 10.
The optimal solution is the tour s*: a b d c a of length 8.
The accuracy ratio of this approximation is
r (sa) = f(sa) / f (s*) = 10 / 8 = 1.25
meaning that tour sa is 25% longer than the optimal tour s*.
It can force us to traverse a very long edge on the last leg of the tour.
Hence, RA = infinity. E.g: Edge (d, a) in the above graph can be made
as large as we wish.
Twice-Around-the-Tree Algorithm
Stage 1: Construct a minimum spanning tree of the graph
corresponding to a given instance of the TSP.
Fig 13.2
The minimum spanning tree of this graph is made up of edges (a, b),
(b, c), (b, d) and (d, e) as shown in the Fig 13.3 below
Fig 13.3
A twice-around-the-tree walk that starts and ends at a is
a, b, c, b, d, e, d, b, a
Eliminating the second b (a shortcut from c to d), and then the second
d and the third b (a shortcut from e to a) yields the Hamiltonian
circuit a, b, c, d, e, a.
Example:
Consider a knapsack with capacity 10 and item information as
follows:
item
weight
value
---------------------------------1
7
Rs.42
2
3
Rs.12
3
4
Rs.40
4
5
Rs.25
Computing the value-to-weight ratios and sorting the items in
nonincreasing order of these efficiency ratios yields
item
weight
value
v/w
-------------------------------------------1
4
Rs.40
10
2
3
4
7
5
3
Rs.42
Rs.25
Rs.12
6
5
4
The greedy algorithm will select the first item of weight 4, skip the
next item of weight 7, select the next item of weight 5, and skip the
last item of weight 3.
i = 1, , n, for
Fig 13.4
The algorithm yields {1. 3. 4}, which is the optimal solution for
this instance
The total number of subsets the algorithm generates before
adding extra elements is