/*************************************************************
 *      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