C++ Reference

C++ Reference: Algorithms

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