Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimal MLB lineup using Knapsack variant

I am writing a program to find the best possible MLB lineup using a knapsack solution. For this I pass in player data which has a players calculated value and salary. The salary will be my "weight" in terms of being a knapsack problem.

My problem is not be able to select players, but rather select the most optimal lineup. I am choosing a pitcher, a center, first baseman, second baseman, third baseman, short stop, and three outfielders. I can do this all successfully. I want my "weight" to be 36,000, but I am currently only choosing a lineup with a total of 21,000.

Here is my knapsack code:

CalculateLineUp.prototype.findOptimalLineUp = function(data, capacity) {
  var items = data.data;
  var idxItem   = 0,
      idxCapSpace = 0,
      idxPosition = 0,
      oldMax    = 0,
      newMax    = 0,
      numItems  = items.length,
      weightMatrix  = new Array(numItems+1),
      keepMatrix    = new Array(numItems+1),
      positionArray = new Array("P", "C", "1B", "2B", "3B", "SS", "OF", "OF", "OF"),
      solutionSet   = [];

  // Setup matrices
  for(idxItem = 0; idxItem < numItems + 1; idxItem++){
    weightMatrix[idxItem] = new Array(capacity+1);
    keepMatrix[idxItem]   = new Array(capacity+1);
  }

  // Build weightMatrix from [0][0] -> [numItems-1][capacity-1]
  for (idxItem = 0; idxItem <= numItems; idxItem++){
    for (idxCapSpace = 0; idxCapSpace <= capacity; idxCapSpace++){  

          // Fill top row and left column with zeros
          if (idxItem === 0 || idxCapSpace === 0){
            weightMatrix[idxItem][idxCapSpace] = 0;
          }

          // If item will fit, decide if there's greater value in keeping it,
          // or leaving it
          else if (items[idxItem-1]["Salary"] <= idxCapSpace){
            newMax = items[idxItem-1]["Value"] + weightMatrix[idxItem-1][idxCapSpace-items[idxItem-1]["Salary"]];
            oldMax = weightMatrix[idxItem-1][idxCapSpace];

            // Update the matrices
            if(newMax > oldMax ){ 
              weightMatrix[idxItem][idxCapSpace]  = newMax;
              keepMatrix[idxItem][idxCapSpace]    = 1;

            }
            else{
              weightMatrix[idxItem][idxCapSpace]  = oldMax; 
              keepMatrix[idxItem][idxCapSpace]    = 0;
            }
          }

          //Else, item can't fit; value and weight are the same as before
           //else
             //weightMatrix[idxItem][idxCapSpace] = weightMatrix[idxItem-1][idxCapSpace];
    }
  }

  // Traverse through keepMatrix ([numItems][capacity] -> [1][?])
  // to create solutionSet
  idxCapSpace = capacity;
  idxItem   = numItems;
  for(idxItem; idxItem < capacity; idxItem--){
    if(keepMatrix[idxItem][idxCapSpace] === 1 && !this.filledAllPositions(items[idxItem - 1]["Position"])){
      solutionSet.push(items[idxItem - 1]);
      idxCapSpace = idxCapSpace - items[idxItem - 1]["Salary"];
    }
  }
  return {"maxValue": weightMatrix[numItems][capacity], "set": solutionSet};
};

Am I making a blatant mistake that I am just not seeing, or is my logic completely off?

like image 974
urnotsam Avatar asked Sep 29 '15 20:09

urnotsam


1 Answers

You are checking the solutionSet right? The logic to accept positions is not a included in the knapsack logic, which means that the solutionSet is a filter on top of the knapsack solution. You did arrive at the right knapsack solution, but because, on top of the solution, you are checking if the position was already filled, a few items were eliminated from the solutionSet (items which were fighting for the same position) and the total weight decreased.

like image 165
Bhargav Ponnapalli Avatar answered Nov 19 '22 17:11

Bhargav Ponnapalli