Computer Science 60
Principles of Computer Science
Fall 2012


Assignment 11: DP and big-O    [100 Points]
Due Monday, December 10 at 11:59pm

This week's homework is a combination of several ideas we've been examining in the computability and complexity portion of CS 60. There are a couple of uncomputability proofs, some algorithms analysis, and a programming review (in Java and Racket) that includes both the use-it-or-lose-it technique and dynamic programming, an approach that speeds up such implementations -- sometimes remarkably so!

Partners:  This week's problems may be done singly or with pair programming.

Problem 1: Change, Inc.

30 points

You have been hired by Change, Inc., a pioneer in the business of making change. Our motto is "Making positive change throughout the world!". Strictly speaking, the change is only "non-negative" since 0 change is possible, but this was a nuance that the PR folks chose to ignore.

Your job is to write software Change, Inc. that will make change in any given currency system using the smallest number of coins/bills. The currency system might have very odd denominations - for example, Gringotts, a potential customer, uses currency whose values are 1, 29, and 493 knuts, respectively - so the software should not impose limits on what denominations it can handle. This software will be embedded in cash registers and used to inform tellers how to make change optimally - or will simply automate the dispensing of change via robotic change-makers.

You may assume that you have "unlimited" quantities of each coin/bill, and that you may use any combination - including repeats - in making change for a given quantity. Also, you may assume that 1 is always present in the list of denominations -- this ensures that it's always possible to make change for any (nonnegative) target!

Your boss, Professor I. Lai, believes that a simple recursive algorithm for this problem will be fast enough for use in the company's cash registers. Although you are skeptical, Prof. Lai is the boss - at least for the moment.

Thus, first task, therefore, is to test the viability of a purely recursive approach. To that end, Dr. Lai has requested both a Prolog predicate and a Racket function that find the shortest-length list of "coins" that sum to a provided target value.

In the end, you'll create three implementations, one in each of Racket, Prolog, and Java. The first two will use recursion (and will remind you about those languages, we hope!) The Java implementation will use dynamic programming -- and run much more efficiently!



Part 2: The Floyd-Warshall all-pairs shortest-paths algorithm

40 points

You've been hired away from Change, Inc. to work for Google and their new stealth-mode version of their mapping service, named GoogleCpam, and which they claim will "completely reverse" the maps experience! GoogleSpam allows users to estimate the shortest distance among any pair of possible spam-locaitons (nodes) in a map (graph).

In particular, you've been asked to implement the main "smarts" of GoogleSpam, i.e., the Floyd-Warshall all-pairs-shortest-paths algorithm. It reads in a graph from a file as an adjacency matrix, computes the shortest paths between every pair of vertices, and then allow a user to make queries against those results.

map files In the hw11.zip archive, there are a number of different map files, named map0.txt, map1.txt, up to map4.txt. Each contains an adjacency matrix that indicates the edge weights from each node to each node. There are zeros in the top row and top column of each file because all of the cities are indexed from 1, not from 0. The extra zeros are padding so that you can read all of the data from the file directly into your data structure and still start indexing the cities/vertices from 1.

Note that, within the map files, no edge from one vertex to another is represented as -1. This is typically represented as some sort of "infinity" value, and the starter code has a data member INF for that purpose. INF is equal to Integer.Max_VALUE. Be careful, however, Java will allow to add or otherwise use INF as an int, and will simply wrap. Thus, INF + INF yields -2! (You'll need conditionals to make sure to avoid this.)

The cities are indexed from 1, not from 0!    Although 1-indexing is not the norm in computer science, it's very useful here, because it means that the 0-index slice of the Floyd-Warshall table can be the original adjacency matrix. Then the 1-index slice of the Floyd-Warshall table can hold all of the shortest paths using the first vertex (with index 1) as possible intermediate node. The 2-index slice of the FW table can then hold all of the shortest paths using also the next vertex (with index 2) as a possible intermediate node, and so on... . Notice that this means that the nth slice of the FW table will hold all of the shortest-path lengths when the algorithm is complete. Note, too, that you will have to make each dimension of size n+1, where n is the number of cities, in order to support indexing from 1 to n!

Here is a brief overview/picture of the included map files:



starter file

The file fw.java contains a little bit of starter code that reads in the first integer from a map file. It also shows how to print a 3d array and has a bit of code to get source and destination vertices from the user via keyboard.

Example results


Here is an example of the completed FW table and, underneath, a few example queries for each of the five maps. In these examples, the paths are printed, but that is the extra-credit portion of this problem -- we'd suggest first getting the shortest-path-distances working, then (if you'd like) returning to work on the paths.

Because some are large, these example results are linked on separate pages:

Warnings/Reminders


  • Since different OSes use different combinations of characaters to indicate newlines, the above examples include all of the data of each map. If our mapfiles are not working, you can create your own by pasting the number of cities and then the adjacency matrix into a new file using a text editor.
  • As you'll recall from our discussion of the Floyd-Warshall algorithm, vertices should be numbered from 1 upwards rather than from 0. Here's why. The algorithm builds a series of tables of path lengths from every src to every dst. The kth "slice" of the table thus represents "the shortest path-length from all src vertices to all dst vertices going through intermediate vertics numbered from 1 to k. By starting at 1, the zeroth table then goes through no intermediate vertices at all, which means it's simply the original graph. By starting vertex-counting at 1, we avoid having a special case for the original graph.
  • Watch out for infinities! INF can be added like any other integer, and it "wraps around" the maximum value an integer can hold, causing surprising results such as INF + INF == -2 ! You'll need special cases to handle infinity appropriately.
  • Extra-credit    For up to +10 points of extra credit, you should also keep track of an array of "parent pointers" and then print out the path from src to dst for each query the user makes. These examples have been included in the sample runs above. How you implement the "parent" table and other details is entirely up to you!
  • Submit your solution in the file called fw.java within the hw11.zip archive.

    Part 3: Big-O running times...

    30 points

    For these questions, you will be analyzing the running time of algorithms. We will be interested in worst-case analysis. You will need to express the worst-case running time using big-O notation. In addition to your answers, be sure to show your reasoning for each of the problems in the hw11pr3.txt file (just as ASCII text).

    Submitting these answers    Include your answers to these problems in the hw11pr3.txt file, which will be within the overall hw11.zip file you submit.




    Extra credit possibilities

    Floyd-Warshall paths

    This assignment's first totally optional - but challenging! - extra credit is worth up to +10 points for an extension of the Floyd-Warshall algorithm so that you can print the shortest paths themselves, not only the lengths of the shortest paths in your implementation of that problem. You can simply include those paths -- as the example outputs show -- with the rest of your FW implementation.

    Improved StoogeSort!

    The second optional - but also challenging! - extra-credit problem worth up to +5 points is to write a recurrence relation and solve it for the Stooge's improved StoogeSort. Improved StoogeSort does the following:

    First, explain in a sentence or two why Improved StoogeSort actually sorts successfully! Next, write a recurrence relation for this Improved StoogeSort algorithm. Finally, "unwind" that recurrence relation and simplify it to state the overall big-O running time of improved stooge sort?

    Place your answer in hw3pr11.txt along with the other part 3 solutions. (Note that if you find the result irrational, you may have gotten it!)