This problem is from the Stanford Open Course CS106B Programming Abstractions Assignment #3 Problem number 6 here.
"You are charged with buying the plumbing pipes for a construction project. Your foreman gives you a list of the varying lengths of pipe needed. Home Depot sells stock pipe in one fixed length. You can divide each stock pipe in any way needed. Your job is to figure out the minimum number of stock pipes required to satisfy the list of requests, thereby saving money and minimizing waste.
The recursive function
CutStock(Vector<int> & requests, int stockLength)
is given a vector of the lengths needed and the stock pipe length. It returns the minimum number of stock pipes needed to service all requests in the vector. For example, if the vector contains{4,3,4,1,7,8}
and the stock pipe length is 10, you can purchase three stock pipes and divide them as follows:{4,4,1} {3,7} {8}
and have two small leftover remnants. There are other possible arrangements that also fit into three stock pipes, but it cannot be done with fewer."
We are allowed to use the specified function as a wrapper function.
Here is my solution code. Is this a good way to solve the problem? Are there any other ways to do so?
/*
* CutStock.cpp
* ------------
* Name: Ratul Sarna
* This program accepts a list of lengths of pipes needed by the
* user and the length of the stock pipe available. It returns the minimum
* number of stock pipes required to satisfy the list of requested pipes
*/
#include "simpio.h"
#include "console.h"
#include "vector.h"
#include <iostream>
using namespace std;
void initializeRequests(Vector<int> & requests);
int cutStock(Vector<int> & requests, int & stockLength);
int recCutStock(Vector<int> & reqCopy, int stockLength);
int main() {
Vector<int> requests;
initializeRequests(requests);
int stockLength = getInteger("Enter the stock length: ");
cout << "Minimum number of stock pipes required to meet the requests = "
<< cutStock(requests, stockLength) << endl;
return 0;
}
/* Accepts the requested pipe lengths and stores them in the vector requests */
void initializeRequests(Vector<int> & requests) {
while (true) {
int votes = getInteger("Enter required length (-1 to quit): ");
if (votes == -1) break;
requests.add(votes);
}
}
/* This is a wrappper function for the actual recursive function that returns
* the minimum number of stockpipes required to satisfy the list of requests */
int cutStock(Vector<int> & requests, int & stockLength) {
// make a deep copy of the given vector of requests so that it can be
// manipulated on
Vector<int> reqCopy = requests;
// call the actual recursive function and return its value
return (recCutStock(reqCopy, stockLength));
}
/* Prototypes for helper functions */
void removeRequestedPipes(Vector<int> & reqCopy, int stockLength, Vector<int> & subsetPipes, int index);
int sumOf(Vector<int> & subsetPipes);
bool isBetterPipe(int checkThisPipe, Vector<int> & subsetPipes, int stockLength, int sum, int & targetIndex);
void swap(int maxIndex, int index, Vector<int> & subsetPipes, Vector<int> & reqCopy);
/* Recursively calculates the minimum number of stock pipes (of stockLength) required
* to satisfy the list of requests
* The basic strategy is-
* 1. If there are requests remaining to be serviced then,
* find a subset of the pipe lengths such that the wastage is minimized when those
* pipes are cut from a pipe of stockLength.
* 2. Remove that subset from the original requested pipe lengths.
* 3. Recursively service the remaining requested pipe lengths
*/
int recCutStock(Vector<int> & reqCopy, int stockLength) {
// if all requests have been met
if (reqCopy.isEmpty()) return 0; // Base Case
Vector<int> subsetPipes;
removeRequestedPipes(reqCopy, stockLength, subsetPipes, 0);
// return 1 stock pipe for the combination removed by the function above and then recursively
// calculate the number of stock pipes needed to service the rest of the requested pipes
return 1 + recCutStock(reqCopy, stockLength);
}
/* Starting with the first requested pipe length (in reqCopy), removes a combination of requested pipes
* from all the given requests (in reqCopy) in such a way that the stock pipe is used with the minimum
* amount of wastage */
void removeRequestedPipes(Vector<int> & reqCopy, int stockLength, Vector<int> & subsetPipes, int index) {
if (index >= reqCopy.size()) return; // Base Case
int sum = sumOf(subsetPipes), targetIndex = 0;
// requested pipe being considered in this call
int currentPipe = reqCopy[index];
// if the current pipe length can be cut from the stockLength pipe then add it into the
// subsetPipes vector and then remove it from the original requests
if (sum + currentPipe <= stockLength) {
subsetPipes.add(currentPipe);
reqCopy.remove(index);
removeRequestedPipes(reqCopy, stockLength, subsetPipes, index);
}
// if the pipe length from original requests is longer any of the pipes in the subsetPipes
// and it can be cut from the stockLength then replace it in the subset
else if (isBetterPipe(reqCopy[index], subsetPipes, stockLength, sum, targetIndex)) {
swap(targetIndex, index, subsetPipes, reqCopy);
removeRequestedPipes(reqCopy, stockLength, subsetPipes, index);
}
else {
removeRequestedPipes(reqCopy, stockLength, subsetPipes, index + 1);
}
}
/* Returns the sum of all the elements in the vector */
int sumOf(Vector<int> & subsetPipes) {
int sum = 0;
for (int i = 0; i < subsetPipes.size(); i++)
sum += subsetPipes[i];
return sum;
}
/* Checks if the pipe length given in "checkThisPipe" is longer than any of the pipes in subsetPipes
* while still being smaller or equal to the stockLength given.
* if yes then update the targetIndex to the element that is smaller and return true.
* else return false */
bool isBetterPipe(int checkThisPipe, Vector<int> & subsetPipes, int stockLength, int sum, int & targetIndex) {
for (int i = 0; i < subsetPipes.size(); i++) {
if ((checkThisPipe > subsetPipes[i])
&& ((sum - subsetPipes[i] + checkThisPipe) <= stockLength)) {
targetIndex = i;
return true;
}
}
return false;
}
/* Swaps the element at minIndex of subsetPipes with the element at index of reqCopy */
void swap(int minIndex, int index, Vector<int> & subsetPipes, Vector<int> & reqCopy) {
int temp = reqCopy[index];
reqCopy[index] = subsetPipes[minIndex];
subsetPipes[minIndex] = temp;
}