COS 226 Programming Assignment 3

Bin packing

Solve the ``bin packing'' problem: Given a set of weights (each between 0 and 1), the bin packing problem is to find a way to assign the weights to a minimal number of bins of capacity 1. This problem is difficult to solve in general, so a number of heuristics have been studied. The ``worst fit'' heuristic is to consider the weights in the order they are presented: if the weight won't fit in any bin, create a new bin, otherwise place the weight in the bin that has the most space. For example, this algorithm would put the weights .1 .3 .7 .8 into three bins (note that this is not the best possible solution). The ``worst fit decreasing'' heuristic is to do worst-fit, but with the weights in decreasing order. This would get the weights .1 .3 .7 .8 into two bins.

Write a program that implements these heurisitics in an efficient manner to find out how many bins are required for a random sequence of N weights in the range 0 to u, using a priority queue ADT. Your task is to design an interface, build two different implementations for the ADT, and write two client programs, one for each of the two heuristics. Your client programs should take N and u as command-line arguments so that, for example, a.out 100 .2 will generate 100 random weights between 0 and .2 and print out the total of the weights generated (best possible number of bins) and the number of bins resulting from applying the heuristic.

First, design an interface that is suited for this task, not necessarily a general-purpose priority queue interface. That is, try to decide which operations are needed by the client programs to complete the task, then provide specifications for those. You certainly will need the insert and delete the maximum operations, and you should think about other low-level operations that would be convenient. The types of items for the ADT should be specified only in the interface. Doing the interface design properly will require some thought (and perhaps a few iterations on the problem).

In conjunction with designing the interface, design (and perhaps implement) the client programs to get an idea of which priority queue operations will be most convenient. Decide what type of data should go on the priority queue, what data structures are needed by the client, and so forth. The needs of the client programs might cause you to modify the interface. Your goal is to later be able to substitute various implementations for the ADT without changing either the interface or the client.

Develop an ordered array implementation for the ADT, which you can use to implement and debug the interface and the client program for the worst fit heuristic. After getting that working, do the other client program. Run both client programs for N=16 and u=.2 and .7, and print out the weights generated and the contents of the bins in some reasonable format. Note: Whatever code you need to print out the contents of the bins is for debugging only, and should not be used for huge values of N. Simplicity and clarity are more important for this part of your program than efficiency.

Next, provide a heap-based implementation for the ADT. Your goal is to be able to do this without changing either client program or the interface at all. Run the client programs for the same values of N and u to make sure that the two priority queue implementations produce the same results.

Using the heap-based implementation, run both client programs for N=100, 1000, 10000, and 100000. Do a few trials for each value with u=.2 and u=.7. In your writeup, comment on the relative effectiveness of the two heuristics.

Extra Credit A. Do implementations for 3-way and 4-way heaps, and run experiments to see which of 2-, 3-, or 4-way heaps are most effective for this problem.

Extra Credit B. Find a heuristic that beats worst-fit and worst-fit decreasing consistently for N=100000.

Due: 11:59PM Thursday, February 26.