/************************************************************* * Program Solving the KNAPSACK problem by brute force * * Author Jakub Holy * * For the subject PAA, LS2002 * ************************************************************* */ #include <iomanip.h> #include "hw1_force.hh" // *** ******************************************** KnapsackProblem KnapsackProblem::KnapsackProblem(int task_id, int nr_items, int max_load, Item **items){ // Parameters KnapsackProblem::task_id = task_id; KnapsackProblem::nr_items = nr_items; KnapsackProblem::max_load = max_load; KnapsackProblem::items = items; // Init other fields config = new bool[nr_items]; best_config = new bool[nr_items]; best_cost = 0; load = 0; cost = 0; index = 0; } // constructor KnapsackProblem::~KnapsackProblem(){ delete [] items; delete [] config; delete [] best_config; } //destructor // *************************************************************** DESCEND /** SOLVE the problem by brute force * The approach: * + We have to try all possible configurations (for which load <= max_load). * A configuration is represented as an array of booleans called config; * if config[i]==true => i-th item is in the solution (in the knapsack). * Thus we have to try all possible bit strings of the length equal to * the number of items. * We start to set values in the string from the beginning (func. descend), * when the end is reached, we return to the nearest included item, exclude * it and set again the rest of the string (from the item to the end; func. * mount()). * The first configuration tried is all ones (if max_load large enough), * the last one all zeros.(Descend creates 1s, mount always adds a 0.) */ void KnapsackProblem::solve(void){ bool cont = true; // Following shared variables (class fields) are used: // index, load, config, best_config, best_cost. // Fields nr_items and max_load are use as constants here. // They are initiated in the constructor. index = load = best_cost = 0; // re-initiate non-pointer variables while (cont) { descend(); cont = mount(); }//while not done }// solve /** DESCEND * Moves forward in the config[] array to the end. * It always sets config[i] to true, unless the max_load would be exceeded. * Before it finishes, it compares the current (complete) configuration * with the best one and saves it, if better. */ void KnapsackProblem::descend(void){ // Descend till the last item (its index is nr_items-1). for(; index < nr_items; index++) { // Check if we can include the current item (don't exceed max_load) if( ( load + items[index]->weight ) <= max_load ){ config[index] = true; // include the item load += items[index]->weight; // add its weight to the total load cost += items[index]->cost; // add its cost to the total one } else { config[index] = false; }//if-else }//while not in a leaf // Decrement index again, now it's invalid, for it equals to nr_items. index--; // Compare the current configuration to the best one and perhaps replace it. if( cost > best_cost ){ best_cost = cost; // save the new best cost // save the configuration for(int i=0; i < nr_items; i++){ best_config[i] = config[i]; }//for }// compare with the best known solution so far } // descend /** MOUNT * Moves backward in the config[] array until config[i]==true found, * set it to false (exlcude it) and finish. Descend will start at config[i+1]. * @return false if cannot mount => we are done */ bool KnapsackProblem::mount(void){ bool reached1 = false; // Exclude the leaf item (by mounting the bottom part of config[] // becomes invalid. Bottom means > index. assert(index == (nr_items-1) ); // exclude the first item, if it is included if ( config[index] ){ config[index] = false;
load -= items[index]->weight; cost -= items[index]->cost; }// if 1st item included // Mount until an included item found or the beginning of config[] reached. while( (!reached1) && (index > 0) ){ // This must be first to mount from a leaf (that's where mount is called from) // The config. with the leaf excluded doesn't need to be tested, because it // can be only worse (by decreasing cost). index--; // If the current item is included, exclude it, inc. index and finish. if ( config[index] ){ reached1 = true; // say we are done here // This item won't be excluded at the beginning of this while // => do it now config[index] = false; // exclude the item load -= items[index]->weight; cost -= items[index]->cost; // descend 1 item, otherwise it would be included again be descend() index++; }// it the current item is included }//while not an included item found or can't mount more return reached1; } // mount // ****************************************************************** printResult void KnapsackProblem::printResult(void){ assert( items!=0 ); cout << task_id << " "<< nr_items <<" " << setw(4) << setiosflags(ios::left)<< best_cost; for(int i=0; i<nr_items; i++ ){ // if( best_config[i] ) cout <<" "<< best_config[i]; }//for cout << endl; }//printResult // ******************************************************************** MAIN // ******************************************************************** MAIN int main(int argc, char **argv){ //Open data file and load the 1st task if ( argc != 2 ) { cout << "Error: Wrong number of parameters.\n"; cout << "Use: bruteforce taskfile\n";
}// if wrong input KnapsackInput *in = new KnapsackInput( argv[1] ); // For all tasks in the file: do { // Solve a task KnapsackProblem *problem = new KnapsackProblem(in->getTaskID(), in->getNr_items(), in->getMax_load(), in->getItems() ); problem->solve(); problem->printResult(); } while ( in->loadNextTask() ); //--------- return 0; }// main