OR-Tools  9.6
knapsack_solver.h
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
15 #define OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
16 
17 #include <math.h>
18 
19 #include <memory>
20 #include <string>
21 #include <vector>
22 
24 #include "ortools/base/logging.h"
25 #include "ortools/base/macros.h"
27 
28 namespace operations_research {
29 
30 class BaseKnapsackSolver;
31 
116  public:
122  enum SolverType {
130 
138 
146 
147 #if defined(USE_CBC)
154 #endif // USE_CBC
155 
162 
163 #if defined(USE_SCIP)
170 #endif // USE_SCIP
171 
172 #if defined(USE_XPRESS)
178  KNAPSACK_MULTIDIMENSION_XPRESS_MIP_SOLVER = 7,
179 #endif
180 
181 #if defined(USE_CPLEX)
187  KNAPSACK_MULTIDIMENSION_CPLEX_MIP_SOLVER = 8,
188 #endif
197  };
198 
199  explicit KnapsackSolver(const std::string& solver_name);
200  KnapsackSolver(SolverType solver_type, const std::string& solver_name);
201  virtual ~KnapsackSolver();
202 
206  void Init(const std::vector<int64_t>& profits,
207  const std::vector<std::vector<int64_t> >& weights,
208  const std::vector<int64_t>& capacities);
209 
213  int64_t Solve();
214 
218  bool BestSolutionContains(int item_id) const;
222  bool IsSolutionOptimal() const { return is_solution_optimal_; }
223  std::string GetName() const;
224 
225  bool use_reduction() const { return use_reduction_; }
226  void set_use_reduction(bool use_reduction) { use_reduction_ = use_reduction; }
227 
233  void set_time_limit(double time_limit_seconds) {
234  time_limit_seconds_ = time_limit_seconds;
235  time_limit_ = std::make_unique<TimeLimit>(time_limit_seconds_);
236  }
237 
238  private:
239  // Trivial reduction of capacity constraints when the capacity is higher than
240  // the sum of the weights of the items. Returns the number of reduced items.
241  int ReduceCapacities(int num_items,
242  const std::vector<std::vector<int64_t> >& weights,
243  const std::vector<int64_t>& capacities,
244  std::vector<std::vector<int64_t> >* reduced_weights,
245  std::vector<int64_t>* reduced_capacities);
246  int ReduceProblem(int num_items);
247  void ComputeAdditionalProfit(const std::vector<int64_t>& profits);
248  void InitReducedProblem(const std::vector<int64_t>& profits,
249  const std::vector<std::vector<int64_t> >& weights,
250  const std::vector<int64_t>& capacities);
251 
252  std::unique_ptr<BaseKnapsackSolver> solver_;
253  std::vector<bool> known_value_;
254  std::vector<bool> best_solution_;
255  bool is_solution_optimal_ = false;
256  std::vector<int> mapping_reduced_item_id_;
257  bool is_problem_solved_;
258  int64_t additional_profit_;
259  bool use_reduction_;
260  double time_limit_seconds_;
261  std::unique_ptr<TimeLimit> time_limit_;
262 
263  DISALLOW_COPY_AND_ASSIGN(KnapsackSolver);
264 };
265 
266 #if !defined(SWIG)
267 // The following code defines needed classes for the KnapsackGenericSolver
268 // class which is the entry point to extend knapsack with new constraints such
269 // as conflicts between items.
270 //
271 // Constraints are enforced using KnapsackPropagator objects, in the current
272 // code there is one propagator per dimension (KnapsackCapacityPropagator).
273 // One of those propagators, named primary propagator, is used to guide the
274 // search, i.e. decides which item should be assigned next.
275 // Roughly speaking the search algorithm is:
276 // - While not optimal
277 // - Select next search node to expand
278 // - Select next item_i to assign (using primary propagator)
279 // - Generate a new search node where item_i is in the knapsack
280 // - Check validity of this new partial solution (using propagators)
281 // - If valid, add this new search node to the search
282 // - Generate a new search node where item_i is not in the knapsack
283 // - Check validity of this new partial solution (using propagators)
284 // - If valid, add this new search node to the search
285 //
286 // TODO(user): Add a new propagator class for conflict constraint.
287 // TODO(user): Add a new propagator class used as a guide when the problem has
288 // several dimensions.
289 
290 // ----- KnapsackAssignment -----
291 // KnapsackAssignment is a small struct used to pair an item with its
292 // assignment. It is mainly used for search nodes and updates.
294  KnapsackAssignment(int _item_id, bool _is_in)
295  : item_id(_item_id), is_in(_is_in) {}
296  int item_id;
297  bool is_in;
298 };
299 
300 // ----- KnapsackItem -----
301 // KnapsackItem is a small struct to pair an item weight with its
302 // corresponding profit.
303 // The aim of the knapsack problem is to pack as many valuable items as
304 // possible. A straight forward heuristic is to take those with the greatest
305 // profit-per-unit-weight. This ratio is called efficiency in this
306 // implementation. So items will be grouped in vectors, and sorted by
307 // decreasing efficiency.
308 // Note that profits are duplicated for each dimension. This is done to
309 // simplify the code, especially the GetEfficiency method and vector sorting.
310 // As there usually are only few dimensions, the overhead should not be an
311 // issue.
312 struct KnapsackItem {
313  KnapsackItem(int _id, int64_t _weight, int64_t _profit)
314  : id(_id), weight(_weight), profit(_profit) {}
315  double GetEfficiency(int64_t profit_max) const {
316  return (weight > 0)
317  ? static_cast<double>(profit) / static_cast<double>(weight)
318  : static_cast<double>(profit_max);
319  }
320 
321  // The 'id' field is used to retrieve the initial item in order to
322  // communicate with other propagators and state.
323  const int id;
324  const int64_t weight;
325  const int64_t profit;
326 };
328 
329 // ----- KnapsackSearchNode -----
330 // KnapsackSearchNode is a class used to describe a decision in the decision
331 // search tree.
332 // The node is defined by a pointer to the parent search node and an
333 // assignment (see KnapsackAssignment).
334 // As the current state is not explicitly stored in a search node, one should
335 // go through the search tree to incrementally build a partial solution from
336 // a previous search node.
338  public:
341  int depth() const { return depth_; }
342  const KnapsackSearchNode* const parent() const { return parent_; }
343  const KnapsackAssignment& assignment() const { return assignment_; }
344 
345  int64_t current_profit() const { return current_profit_; }
346  void set_current_profit(int64_t profit) { current_profit_ = profit; }
347 
348  int64_t profit_upper_bound() const { return profit_upper_bound_; }
349  void set_profit_upper_bound(int64_t profit) { profit_upper_bound_ = profit; }
350 
351  int next_item_id() const { return next_item_id_; }
352  void set_next_item_id(int id) { next_item_id_ = id; }
353 
354  private:
355  // 'depth' field is used to navigate efficiently through the search tree
356  // (see KnapsackSearchPath).
357  int depth_;
358  const KnapsackSearchNode* const parent_;
359  KnapsackAssignment assignment_;
360 
361  // 'current_profit' and 'profit_upper_bound' fields are used to sort search
362  // nodes using a priority queue. That allows to pop the node with the best
363  // upper bound, and more importantly to stop the search when optimality is
364  // proved.
365  int64_t current_profit_;
366  int64_t profit_upper_bound_;
367 
368  // 'next_item_id' field allows to avoid an O(number_of_items) scan to find
369  // next item to select. This is done for free by the upper bound computation.
370  int next_item_id_;
371 
372  DISALLOW_COPY_AND_ASSIGN(KnapsackSearchNode);
373 };
374 
375 // ----- KnapsackSearchPath -----
376 // KnapsackSearchPath is a small class used to represent the path between a
377 // node to another node in the search tree.
378 // As the solution state is not stored for each search node, the state should
379 // be rebuilt at each node. One simple solution is to apply all decisions
380 // between the node 'to' and the root. This can be computed in
381 // O(number_of_items).
382 //
383 // However, it is possible to achieve better average complexity. Two
384 // consecutively explored nodes are usually close enough (i.e., much less than
385 // number_of_items) to benefit from an incremental update from the node
386 // 'from' to the node 'to'.
387 //
388 // The 'via' field is the common parent of 'from' field and 'to' field.
389 // So the state can be built by reverting all decisions from 'from' to 'via'
390 // and then applying all decisions from 'via' to 'to'.
392  public:
394  const KnapsackSearchNode& to);
395  void Init();
396  const KnapsackSearchNode& from() const { return from_; }
397  const KnapsackSearchNode& via() const { return *via_; }
398  const KnapsackSearchNode& to() const { return to_; }
400  int depth) const;
401 
402  private:
403  const KnapsackSearchNode& from_;
404  const KnapsackSearchNode* via_; // Computed in 'Init'.
405  const KnapsackSearchNode& to_;
406 
407  DISALLOW_COPY_AND_ASSIGN(KnapsackSearchPath);
408 };
409 
410 // ----- KnapsackState -----
411 // KnapsackState represents a partial solution to the knapsack problem.
413  public:
414  KnapsackState();
415 
416  // Initializes vectors with number_of_items set to false (i.e. not bound yet).
417  void Init(int number_of_items);
418  // Updates the state by applying or reverting a decision.
419  // Returns false if fails, i.e. trying to apply an inconsistent decision
420  // to an already assigned item.
421  bool UpdateState(bool revert, const KnapsackAssignment& assignment);
422 
423  int GetNumberOfItems() const { return is_bound_.size(); }
424  bool is_bound(int id) const { return is_bound_.at(id); }
425  bool is_in(int id) const { return is_in_.at(id); }
426 
427  private:
428  // Vectors 'is_bound_' and 'is_in_' contain a boolean value for each item.
429  // 'is_bound_(item_i)' is false when there is no decision for item_i yet.
430  // When item_i is bound, 'is_in_(item_i)' represents the presence (true) or
431  // the absence (false) of item_i in the current solution.
432  std::vector<bool> is_bound_;
433  std::vector<bool> is_in_;
434 
435  DISALLOW_COPY_AND_ASSIGN(KnapsackState);
436 };
437 
438 // ----- KnapsackPropagator -----
439 // KnapsackPropagator is the base class for modeling and propagating a
440 // constraint given an assignment.
441 //
442 // When some work has to be done both by the base and the derived class,
443 // a protected pure virtual method ending by 'Propagator' is defined.
444 // For instance, 'Init' creates a vector of items, and then calls
445 // 'InitPropagator' to let the derived class perform its own initialization.
447  public:
448  explicit KnapsackPropagator(const KnapsackState& state);
449  virtual ~KnapsackPropagator();
450 
451  // Initializes data structure and then calls InitPropagator.
452  void Init(const std::vector<int64_t>& profits,
453  const std::vector<int64_t>& weights);
454 
455  // Updates data structure and then calls UpdatePropagator.
456  // Returns false when failure.
457  bool Update(bool revert, const KnapsackAssignment& assignment);
458  // ComputeProfitBounds should set 'profit_lower_bound_' and
459  // 'profit_upper_bound_' which are constraint specific.
460  virtual void ComputeProfitBounds() = 0;
461  // Returns the id of next item to assign.
462  // Returns kNoSelection when all items are bound.
463  virtual int GetNextItemId() const = 0;
464 
465  int64_t current_profit() const { return current_profit_; }
466  int64_t profit_lower_bound() const { return profit_lower_bound_; }
467  int64_t profit_upper_bound() const { return profit_upper_bound_; }
468 
469  // Copies the current state into 'solution'.
470  // All unbound items are set to false (i.e. not in the knapsack).
471  // When 'has_one_propagator' is true, CopyCurrentSolutionPropagator is called
472  // to have a better solution. When there is only one propagator
473  // there is no need to check the solution with other propagators, so the
474  // partial solution can be smartly completed.
475  void CopyCurrentStateToSolution(bool has_one_propagator,
476  std::vector<bool>* solution) const;
477 
478  protected:
479  // Initializes data structure. This method is called after initialization
480  // of KnapsackPropagator data structure.
481  virtual void InitPropagator() = 0;
482 
483  // Updates internal data structure incrementally. This method is called
484  // after update of KnapsackPropagator data structure.
485  virtual bool UpdatePropagator(bool revert,
486  const KnapsackAssignment& assignment) = 0;
487 
488  // Copies the current state into 'solution'.
489  // Only unbound items have to be copied as CopyCurrentSolution was already
490  // called with current state.
491  // This method is useful when a propagator is able to find a better solution
492  // than the blind instantiation to false of unbound items.
494  std::vector<bool>* solution) const = 0;
495 
496  const KnapsackState& state() const { return state_; }
497  const std::vector<KnapsackItemPtr>& items() const { return items_; }
498 
499  void set_profit_lower_bound(int64_t profit) { profit_lower_bound_ = profit; }
500  void set_profit_upper_bound(int64_t profit) { profit_upper_bound_ = profit; }
501 
502  private:
503  std::vector<KnapsackItemPtr> items_;
504  int64_t current_profit_;
505  int64_t profit_lower_bound_;
506  int64_t profit_upper_bound_;
507  const KnapsackState& state_;
508 
509  DISALLOW_COPY_AND_ASSIGN(KnapsackPropagator);
510 };
511 
512 // ----- KnapsackCapacityPropagator -----
513 // KnapsackCapacityPropagator is a KnapsackPropagator used to enforce
514 // a capacity constraint.
515 // As a KnapsackPropagator is supposed to compute profit lower and upper
516 // bounds, and get the next item to select, it can be seen as a 0-1 Knapsack
517 // solver. The most efficient way to compute the upper bound is to iterate on
518 // items in profit-per-unit-weight decreasing order. The break item is
519 // commonly defined as the first item for which there is not enough remaining
520 // capacity. Selecting this break item as the next-item-to-assign usually
521 // gives the best results (see Greenberg & Hegerich).
522 //
523 // This is exactly what is implemented in this class.
524 //
525 // When there is only one propagator, it is possible to compute a better
526 // profit lower bound almost for free. During the scan to find the
527 // break element all unbound items are added just as if they were part of
528 // the current solution. This is used in both ComputeProfitBounds and
529 // CopyCurrentSolutionPropagator.
530 // For incrementality reasons, the ith item should be accessible in O(1). That's
531 // the reason why the item vector has to be duplicated 'sorted_items_'.
533  public:
535  ~KnapsackCapacityPropagator() override;
536  void ComputeProfitBounds() override;
537  int GetNextItemId() const override { return break_item_id_; }
538 
539  protected:
540  // Initializes KnapsackCapacityPropagator (e.g., sort items in decreasing
541  // order).
542  void InitPropagator() override;
543  // Updates internal data structure incrementally (i.e., 'consumed_capacity_')
544  // to avoid a O(number_of_items) scan.
545  bool UpdatePropagator(bool revert,
546  const KnapsackAssignment& assignment) override;
548  std::vector<bool>* solution) const override;
549 
550  private:
551  // An obvious additional profit upper bound corresponds to the linear
552  // relaxation: remaining_capacity * efficiency of the break item.
553  // It is possible to do better in O(1), using Martello-Toth bound U2.
554  // The main idea is to enforce integrality constraint on the break item,
555  // ie. either the break item is part of the solution, either it is not.
556  // So basically the linear relaxation is done on the item before the break
557  // item, or the one after the break item.
558  // This is what GetAdditionalProfit method implements.
559  int64_t GetAdditionalProfit(int64_t remaining_capacity,
560  int break_item_id) const;
561 
562  const int64_t capacity_;
563  int64_t consumed_capacity_;
564  int break_item_id_;
565  std::vector<KnapsackItemPtr> sorted_items_;
566  int64_t profit_max_;
567 
568  DISALLOW_COPY_AND_ASSIGN(KnapsackCapacityPropagator);
569 };
570 
571 // ----- BaseKnapsackSolver -----
572 // This is the base class for knapsack solvers.
574  public:
575  explicit BaseKnapsackSolver(const std::string& solver_name)
576  : solver_name_(solver_name) {}
577  virtual ~BaseKnapsackSolver() {}
578 
579  // Initializes the solver and enters the problem to be solved.
580  virtual void Init(const std::vector<int64_t>& profits,
581  const std::vector<std::vector<int64_t> >& weights,
582  const std::vector<int64_t>& capacities) = 0;
583 
584  // Gets the lower and upper bound when the item is in or out of the knapsack.
585  // To ensure objects are correctly initialized, this method should not be
586  // called before ::Init.
587  virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
588  int64_t* lower_bound,
589  int64_t* upper_bound);
590 
591  // Solves the problem and returns the profit of the optimal solution.
592  virtual int64_t Solve(TimeLimit* time_limit, bool* is_solution_optimal) = 0;
593 
594  // Returns true if the item 'item_id' is packed in the optimal knapsack.
595  virtual bool best_solution(int item_id) const = 0;
596 
597  virtual std::string GetName() const { return solver_name_; }
598 
599  private:
600  const std::string solver_name_;
601 };
602 
603 // ----- KnapsackGenericSolver -----
604 // KnapsackGenericSolver is the multi-dimensional knapsack solver class.
605 // In the current implementation, the next item to assign is given by the
606 // primary propagator. Using SetPrimaryPropagator allows changing the default
607 // (propagator of the first dimension), and selecting another dimension when
608 // more constrained.
609 // TODO(user): In the case of a multi-dimensional knapsack problem, implement
610 // an aggregated propagator to combine all dimensions and give a better guide
611 // to select the next item (see, for instance, Dobson's aggregated efficiency).
613  public:
614  explicit KnapsackGenericSolver(const std::string& solver_name);
615  ~KnapsackGenericSolver() override;
616 
617  // Initializes the solver and enters the problem to be solved.
618  void Init(const std::vector<int64_t>& profits,
619  const std::vector<std::vector<int64_t> >& weights,
620  const std::vector<int64_t>& capacities) override;
621  int GetNumberOfItems() const { return state_.GetNumberOfItems(); }
622  void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in,
623  int64_t* lower_bound,
624  int64_t* upper_bound) override;
625 
626  // Sets which propagator should be used to guide the search.
627  // 'primary_propagator_id' should be in 0..p-1 with p the number of
628  // propagators.
629  void set_primary_propagator_id(int primary_propagator_id) {
630  primary_propagator_id_ = primary_propagator_id;
631  }
632 
633  // Solves the problem and returns the profit of the optimal solution.
634  int64_t Solve(TimeLimit* time_limit, bool* is_solution_optimal) override;
635  // Returns true if the item 'item_id' is packed in the optimal knapsack.
636  bool best_solution(int item_id) const override {
637  return best_solution_.at(item_id);
638  }
639 
640  private:
641  // Clears internal data structure.
642  void Clear();
643 
644  // Updates all propagators reverting/applying all decision on the path.
645  // Returns true if fails. Note that, even if fails, all propagators should
646  // be updated to be in a stable state in order to stay incremental.
647  bool UpdatePropagators(const KnapsackSearchPath& path);
648  // Updates all propagators reverting/applying one decision.
649  // Return true if fails. Note that, even if fails, all propagators should
650  // be updated to be in a stable state in order to stay incremental.
651  bool IncrementalUpdate(bool revert, const KnapsackAssignment& assignment);
652  // Updates the best solution if the current solution has a better profit.
653  void UpdateBestSolution();
654 
655  // Returns true if new relevant search node was added to the nodes array, that
656  // means this node should be added to the search queue too.
657  bool MakeNewNode(const KnapsackSearchNode& node, bool is_in);
658 
659  // Gets the aggregated (min) profit upper bound among all propagators.
660  int64_t GetAggregatedProfitUpperBound() const;
661  bool HasOnePropagator() const { return propagators_.size() == 1; }
662  int64_t GetCurrentProfit() const {
663  return propagators_.at(primary_propagator_id_)->current_profit();
664  }
665  int64_t GetNextItemId() const {
666  return propagators_.at(primary_propagator_id_)->GetNextItemId();
667  }
668 
669  std::vector<KnapsackPropagator*> propagators_;
670  int primary_propagator_id_;
671  std::vector<KnapsackSearchNode*> search_nodes_;
672  KnapsackState state_;
673  int64_t best_solution_profit_;
674  std::vector<bool> best_solution_;
675 
676  DISALLOW_COPY_AND_ASSIGN(KnapsackGenericSolver);
677 };
678 #endif // SWIG
679 } // namespace operations_research
680 
681 #endif // OR_TOOLS_ALGORITHMS_KNAPSACK_SOLVER_H_
virtual void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64_t *lower_bound, int64_t *upper_bound)
virtual int64_t Solve(TimeLimit *time_limit, bool *is_solution_optimal)=0
virtual void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities)=0
BaseKnapsackSolver(const std::string &solver_name)
virtual std::string GetName() const
virtual bool best_solution(int item_id) const =0
KnapsackCapacityPropagator(const KnapsackState &state, int64_t capacity)
bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment) override
void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const override
KnapsackGenericSolver(const std::string &solver_name)
void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities) override
int64_t Solve(TimeLimit *time_limit, bool *is_solution_optimal) override
bool best_solution(int item_id) const override
void GetLowerAndUpperBoundWhenItem(int item_id, bool is_item_in, int64_t *lower_bound, int64_t *upper_bound) override
void set_primary_propagator_id(int primary_propagator_id)
void Init(const std::vector< int64_t > &profits, const std::vector< int64_t > &weights)
void CopyCurrentStateToSolution(bool has_one_propagator, std::vector< bool > *solution) const
virtual bool UpdatePropagator(bool revert, const KnapsackAssignment &assignment)=0
virtual int GetNextItemId() const =0
const KnapsackState & state() const
const std::vector< KnapsackItemPtr > & items() const
virtual void CopyCurrentStateToSolutionPropagator(std::vector< bool > *solution) const =0
KnapsackPropagator(const KnapsackState &state)
bool Update(bool revert, const KnapsackAssignment &assignment)
KnapsackSearchNode(const KnapsackSearchNode *const parent, const KnapsackAssignment &assignment)
const KnapsackAssignment & assignment() const
const KnapsackSearchNode *const parent() const
const KnapsackSearchNode * MoveUpToDepth(const KnapsackSearchNode &node, int depth) const
const KnapsackSearchNode & via() const
KnapsackSearchPath(const KnapsackSearchNode &from, const KnapsackSearchNode &to)
const KnapsackSearchNode & from() const
const KnapsackSearchNode & to() const
This library solves knapsack problems.
bool BestSolutionContains(int item_id) const
Returns true if the item 'item_id' is packed in the optimal knapsack.
KnapsackSolver(const std::string &solver_name)
void set_time_limit(double time_limit_seconds)
Time limit in seconds.
int64_t Solve()
Solves the problem and returns the profit of the optimal solution.
SolverType
Enum controlling which underlying algorithm is used.
@ KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER
SCIP based solver.
@ KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER
Generic Solver.
@ KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER
Dynamic Programming approach for single dimension problems.
@ KNAPSACK_DIVIDE_AND_CONQUER_SOLVER
Divide and Conquer approach for single dimension problems.
@ KNAPSACK_64ITEMS_SOLVER
Optimized method for single dimension small problems.
@ KNAPSACK_BRUTE_FORCE_SOLVER
Brute force method.
@ KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER
CBC Based Solver.
bool IsSolutionOptimal() const
Returns true if the solution was proven optimal.
void set_use_reduction(bool use_reduction)
void Init(const std::vector< int64_t > &profits, const std::vector< std::vector< int64_t > > &weights, const std::vector< int64_t > &capacities)
Initializes the solver and enters the problem to be solved.
void Init(int number_of_items)
bool UpdateState(bool revert, const KnapsackAssignment &assignment)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
ModelSharedTimeLimit * time_limit
const int64_t profit_max
Collection of objects used to extend the Constraint Solver library.
KnapsackItem * KnapsackItemPtr
IntVar * upper_bound
Definition: routing.cc:1087
IntVar * lower_bound
Definition: routing.cc:1086
int64_t capacity
KnapsackAssignment(int _item_id, bool _is_in)
double GetEfficiency(int64_t profit_max) const
KnapsackItem(int _id, int64_t _weight, int64_t _profit)