Printingbinarysearchpdf
Printingbinarysearchpdf
We have seen examples of the D&C paradigm in the previous sections of this book: Various
sorting algorithms (e.g. Quick Sort, Merge Sort, Heap Sort) and Binary Search in Section
2.2 utilize this paradigm. The way data is organized in Binary Search Tree, Heap, Segment
Tree, and Fenwick Tree in Section 2.3, 2.4.3, and 2.4.4 also relies upon the D&C paradigm.
84
CHAPTER 3. PROBLEM SOLVING PARADIGMS
c Steven & Felix
itself, we have found the solution. As there are Q queries, this approach runs in O(QN) (the
input tree can be a sorted linked list, or rope, of length N) and will get a TLE as N ≤ 80K
and Q ≤ 20K.
A better solution is to store all the 20K queries (we do not have to answer them im-
mediately). Traverse the tree just once starting from the root using the O(N) preorder
tree traversal algorithm (Section 4.7.2). This preorder tree traversal is slightly modified to
remember the partial root-to-current-vertex sequence as it executes. The array is always
sorted because the vertices along the root-to-current-vertex path have increasing weights,
see Figure 3.3 (right). The preorder tree traversal on the tree shown in Figure 3.3 (left)
produces the following partial root-to-current-vertex sorted array: {{3}, {3, 5}, {3, 5, 7},
{3, 5, 7, 8}, backtrack, {3, 5, 7, 9}, backtrack, backtrack, backtrack, {3, 8}, backtrack,
{3, 6}, {3, 6, 20}, backtrack, {3, 6, 10}, and finally {3, 6, 10, 20}, backtrack, backtrack,
backtrack (done)}.
During the preorder traversal, when we land on a queried vertex, we can perform a
O(log N) binary search (to be precise: lower bound) on the partial root-to-current-vertex
weight array to obtain the ancestor closest to the root with a value of at least P , recording
these solutions. Finally, we can perform a simple O(Q) iteration to output the results. The
overall time complexity of this approach is O(Q log N), which is now manageable given the
input bounds.
Bisection Method
We have discussed the applications of Binary Searches in finding items in static sorted
sequences. However, the binary search principle4 can also be used to find the root of a
function that may be difficult to compute directly.
Example: You buy a car with loan and now want to pay the loan in monthly installments
of d dollars for m months. Suppose the value of the car is originally v dollars and the bank
charges an interest rate of i% for any unpaid loan at the end of each month. What is the
amount of money d that you must pay per month (to 2 digits after the decimal point)?
Suppose d = 576.19, m = 2, v = 1000, and i = 10%. After one month, your debt
becomes 1000 × (1.1) − 576.19 = 523.81. After two months, your debt becomes 523.81 ×
(1.1) − 576.19 ≈ 0. If we are only given m = 2, v = 1000, and i = 10%, how would we
determine that d = 576.19? In other words, find the root d such that the debt payment
function f (d, m, v, i) ≈ 0.
An easy way to solve this root finding problem is to use the bisection method. We pick
a reasonable range as a starting point. We want to fix d within the range [a..b] where
4
We use the term ‘binary search principle’ to refer to the D&C approach of halving the range of possible
answers. The ‘binary search algorithm’ (finding index of an item in a sorted array), the ‘bisection method’
(finding the root of a function), and ‘binary search the answer’ (discussed in the next subsection) are all
instances of this principle.
85
3.3. DIVIDE AND CONQUER
c Steven & Felix
a = 0.01 as we have to pay at least one cent and b = (1 + i%) × v as the earliest we can
complete the payment is m = 1 if we pay exactly (1 + i%) × v dollars after one month. In
this example, b = (1 + 0.1) × 1000 = 1100.00 dollars. For the bisection method to work5 ,
we must ensure that the function values of the two extreme points in the initial Real range
[a..b], i.e. f (a) and f (b) have opposite signs (this is true for the computed a and b above).
a b d = a+b
2
status: f (d, m, v, i) action
0.01 1100.00 550.005 undershoot by 54.9895 increase d
550.005 1100.00 825.0025 overshoot by 522.50525 decrease d
550.005 825.0025 687.50375 overshoot by 233.757875 decrease d
550.005 687.50375 618.754375 overshoot by 89.384187 decrease d
550.005 618.754375 584.379688 overshoot by 17.197344 decrease d
550.005 584.379688 567.192344 undershoot by 18.896078 increase d
567.192344 584.379688 575.786016 undershoot by 0.849366 increase d
... ... ... a few iterations later . . . ...
... ... 576.190476 stop; error is now less than answer = 576.19
Notice that bisection method only requires O(log2 ((b − a)/)) iterations to get an answer
that is good enough (the error is smaller than the threshold error that we can tolerate).
In this example, bisection method only takes log2 1099.99/ tries. Using a small = 1e-9,
this yields only ≈ 40 iterations. Even if we use a smaller = 1e-15, we will still only need
≈ 60 tries. Notice that the number of tries is small. The bisection method is much more
efficient compared to exhaustively evaluating each possible value of d =[0.01..1100.00]/
for this example function. Note: The bisection method can be written with a loop that tries
the values of d ≈ 40 to 60 times (see our implementation in the ‘binary search the answer’
discussion below).
86
CHAPTER 3. PROBLEM SOLVING PARADIGMS
c Steven & Felix
will not bring your jeep safely to the goal event. On the other hand, setting your jeep fuel
tank volume to any value between [X..10000.000] will bring your jeep safely to the goal
event, usually with some fuel left. This property allows us to binary search the answer X!
We can use the following code to obtain the solution for this problem.
#define EPS 1e-9 // this value is adjustable; 1e-9 is usually small enough
bool can(double f) { // details of this simulation is omitted
// return true if the jeep can reach goal state with fuel tank capacity f
// return false otherwise
}
Note that some programmers choose to use a constant number of refinement iterations
instead of allowing the number of iterations to vary dynamically to avoid precision errors
when testing fabs(hi - lo) > EPS and thus being trapped in an infinite loop. The only
changes required to implement this approach are shown below. The other parts of the code
are the same as above.
Exercise 3.3.1.1: There is an alternative solution for UVa 11935 that does not use ‘binary
search the answer’ technique. Can you spot it?
Exercise 3.3.1.2*: The example shown here involves binary-searching the answer where
the answer is a floating point number. Modify the code to solve ‘binary search the answer’
problems where the answer lies in an integer range!
87
3.3. DIVIDE AND CONQUER
c Steven & Felix
programming contests is the Binary Search principle. If you want to do well in programming
contests, please spend time practicing the various ways to apply it.
Once you are more familiar with the ‘Binary Search the Answer’ technique discussed in
this section, please explore Section 8.4.1 for a few more programming exercises that use this
technique with other algorithm that we will discuss in the latter parts of this book.
We notice that there are not that many D&C problems outside of our binary search
categorization. Most D&C solutions are ‘geometry-related’ or ‘problem specific’, and thus
cannot be discussed in detail in this book. However, we will encounter some of them in
Section 8.4.1 (binary search the answer plus geometry formulas), Section 9.14 (Inversion
Index), Section 9.21 (Matrix Power), and Section 9.29 (Selection Problem).
88
CHAPTER 3. PROBLEM SOLVING PARADIGMS
c Steven & Felix
3.4 Greedy
An algorithm is said to be greedy if it makes the locally optimal choice at each step with the
hope of eventually reaching the globally optimal solution. In some cases, greedy works—the
solution is short and runs efficiently. For many others, however, it does not. As discussed
in other typical Computer Science textbooks, e.g. [7, 38], a problem must exhibit these two
properties in order for a greedy algorithm to work:
1. It has optimal sub-structures.
Optimal solution to the problem contains optimal solutions to the sub-problems.
2. It has the greedy property (difficult to prove in time-critical contest environment!).
If we make a choice that seems like the best at the moment and proceed to solve the
remaining subproblem, we reach the optimal solution. We will never have to reconsider
our previous choices.
3.4.1 Examples
Coin Change - The Greedy Version
Problem description: Given a target amount V cents and a list of denominations of n coins,
i.e. we have coinValue[i] (in cents) for coin types i ∈ [0..n-1], what is the minimum
number of coins that we must use to represent amount V ? Assume that we have an unlimited
supply of coins of any type. Example: If n = 4, coinValue = {25, 10, 5, 1} cents6 , and
we want to represent V = 42 cents, we can use this Greedy algorithm: Select the largest
coin denomination which is not greater than the remaining amount, i.e. 42-25 = 17 → 17-10
= 7 → 7-5 = 2 → 2-1 = 1 → 1-1 = 0, a total of 5 coins. This is optimal.
The problem above has the two ingredients required for a successful greedy algorithm:
1. It has optimal sub-structures.
We have seen that in our quest to represent 42 cents, we used 25+10+5+1+1.
This is an optimal 5-coin solution to the original problem!
Optimal solutions to sub-problem are contained within the 5-coin solution, i.e.
a. To represent 17 cents, we can use 10+5+1+1 (part of the solution for 42 cents),
b. To represent 7 cents, we can use 5+1+1 (also part of the solution for 42 cents), etc
2. It has the greedy property: Given every amount V , we can greedily subtract from it
the largest coin denomination which is not greater than this amount V . It can be
proven (not shown here for brevity) that using any other strategies will not lead to an
optimal solution, at least for this set of coin denominations.
However, this greedy algorithm does not work for all sets of coin denominations. Take for
example {4, 3, 1} cents. To make 6 cents with that set, a greedy algorithm would choose 3
coins {4, 1, 1} instead of the optimal solution that uses 2 coins {3, 3}. The general version
of this problem is revisited later in Section 3.5.2 (Dynamic Programming).
89