# Class 19: A Stamp Problem

Back to Recursion, Revisited. On to Sorting Algorithms.

Held Wednesday, February 24

Summary

• Algorithm design techniques
• Greed
• Dynamic programming
• Applications
• Fibonacci numbers
• Computing stamps

Contents

Handouts

Notes

• Any questions on the exam?
• As you may be able to tell, I've rearranged the syllabus somewhat.
• The pause for breath is gone, fulfilling its intended purpose of leaving space to expand into.
• The next few days will probably be more lecture-oriented than lab oriented (in fact, most of the rest of the term will be more lecture-oriented).
• Today, we'll try using the new SmartBoard.
• I'd like feedback on what you think about it all.
• I'll do more typing than writing, hopefully ameliorating all those problems with my handwriting.
• After class, I'll do my best to get reproductions of my notes online.
• Mr. Flynt has figured out how to make emacs print particularly nicely. The new typefaces are used on the screen, and also used in the pretty-printed buffers. Briefly, add these lines to the bottom of your .emacs file:
(make-face-italic font-lock-comment-face)
(make-face-bold font-lock-keyword-face)
(make-face-bold font-lock-function-name-face)
(make-face-bold font-lock-type-face)

• You can play around with variants.

• Suppose you went to the post office and wanted to send a package that costs \$3.31 to mail. The postal meter is down, so you'll need to buy stamps.
• How few stamps can you buy to make \$3.31 in postage?
• What other information do you need to solve this problem?
• As computer scientists, we like to generalize problems. So, we might say, given a postage, p, and an array of stamp prices, S, determine the minimum number of stamps to make up postage p.
• We'll leave the precise stamps to buy as an exercise :-)
• What preconditions and postconditions might you put on an algorithm to solve this problem?

### A Greedy Solution

• One design technique that we might apply to this problem is that of greediness. We repeatedly choose the largest possible value.
• In Java
/**
* Compute the minimum number of stamps to make up some postage.
* <br>Precondition: The postage is nonnegative.
* <br>Precondition: Stamp prices are positive.
* <br>Precondition: The stamp prices are sorted in increasing order.
* <br>Precondition: There is a penny stamp (so that we can make
*   any price)
* <br>Postcondition: Computes the minimum number of stamps.
*/
public int minimumStamps(int postage, int[] stampPrices) {
/* Strategy: this algorithm uses a greedy technique.  We
* repeatedly buy the largest possible stamp.
*/
// The number of stamps needed.
int count = 0;
// The index of the most expensive stamp to consider.
int stamp = stampPrices.length - 1;
// Repeatedly choose a price and remove copies until the
// postage reaches 0.
while (postage > 0) {
// Find the most expensive stamp we still need.
while (stampPrices[stamp] > postage) --stamp;
// Buy a stamp at the price.
postage -= stampPrices[stamp];
count +- 1;
} // while (postage > 0)
// That's it, we're done.
return count;
} // minimumStamps(int, int[])

• Unfortunately, this doesn't work for all cases (particularly not if we don't include the requirement about penny stamps).

### A Recursive Solution

• It looks like we'll need another way to look at the problem.
• It's clear that buying the most expensive stamp at each step doesn't work.
• But we do have to buy some stamp.
• Suppose we need to buy a stamp at price x in order to get the minimum solution. How many stamps will that solution require?
• 1 + (number of stamps to make up postage-x)
• But we don't know which price stamp we'll have to buy.
• So we'll guess each price.
for each stamp price, x
compute the minumum number of stamps for postage-x
choose the minimum of all those prices

• Let's now rewrite this in Java.
/**
* Compute the minimum number of stamps required for some postage.
* All values are expressed in terms of cents.
* Pre: postage >= 0.
* Pre: stamp prices are positive.
* Pre: fewer than Integer.MAX_VALUE stamps are required.
* Post: returns the minimum number of stamps required for that
*   postage (but does not print out which stamps).
* Post: throws an exception if it's not possible to make that
*   postage with the given stamp prices.
*/
public int minStamps(int postage, int[] stampPrices)
throws Exception
{
// Our guess.  Initialized to some outlandish value so that
// we can tell if we don't have a solution.
int guess = Integer.MAX_VALUE;
// The next guess.  Used as we step through potential prices.
int nextGuess;
// Base case: no stamps are required for no postage.
if (postage == 0) return 0;
// Recursive case: try each price until we find the smallest.
else {
for(int i = 0; i < stampPrices.length; ++i) {
// If the current stamp is cheap enough, try to
// improve our guess.
if (stampPrices[i] <= postage) {
try {
// Make a new guess
nextGuess = 1 + minStamps(postage-stampPrices[i],
stampPrices);
if (nextGuess < guess) guess = nextGuess;
} // try
// No number of stamps could be used for revised postage.
// Don't update our guess.
catch (Exception e) { }
} // if the price was cheap enough.
} // for
// We've now computed the minimum number of stamps.  Ensure
// that it's a reasonable value.
if (guess != Integer.MAX_VALUE) return guess;
// Otherwise, there was no way to sum stamp prices to the given
// postage, so throw an exception
else throw new Exception("No combination of stamps for " + postage);
} // Recursive case
} // minStamps(int,int[])

• Unfortunately, this seems to require a lot of work
• (How much?)
• You can try it out as you try to derive an answer. Try
• % ji StampComputer 7 2
• % ji StampComputer 8 1 3 5
• % ji StampComputer 8 5 3 1
• % ji StampComputer 9 1 3 5
• % ji StampComputer 27 10 9 1

### Improving the Recursive Solution

• You might observe that the same prices are computed again and again and again.
• Since each computation involves many subcomputation, it behooves us to avoid repeated computations.
• We'll put the results in an array, MIN_STAMPS.
int[] MIN_STAMPS

• We need to initialize it (we'll do so in the first call).
MIN_STAMPS = new int[postage+1];
MIN_STAMPS[0] = 0;
for (int i = 1; i <= postage; ++i) {
MIN_STAMPS[i] = Integer.MAX_VALUE;
} // for

• Before computing the number of stamps for a price, we check the table.
if (MIN_STAMPS[postage] != Integer.MAX_VALUE)
return MIN_STAMPS[postage];

• After computing the number of stamps for a price, we update the table.
MIN_STAMPS[postage] = guess;

• Now, we don't repeat work. In effect, we compute the number of stamps for each postage once, but we check each stamp price for each postage.
• The running time should then be O(postage*numberOfStampPrices)
• Try some of the same examples using NewStampComputer.java
• % ji NewStampComputer 7 2
• % ji NewStampComputer 8 1 3 5
• % ji NewStampComputer 8 5 3 1
• % ji NewStampComputer 9 1 3 5
• % ji NewStampComputer 27 10 9 1
• You can also do this as an iterative algorithm, starting at 1 and working up to postage.

History

• Created Monday, January 11, 1999.
• Added short summary on Friday, January 22, 1999.
• Began filling in details on Tuesday, February 23, 1999. The first set of details (specification of the stamps problem and the greedy solution) were taken from the previous outline (and had been created anew for that outline).
• Added the dynamic programming solution on Wednesday, February 24, 1999.
• Removed a section on algorithm design techniques on Friday, February 26, 1999.

Back to Recursion, Revisited. On to Sorting Algorithms.

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.