Wie das Problem mit mehreren Rucksäcken beinhaltet auch das Packen des Containers Artikel in Kisten verpackt. Das Problem mit dem Behälter ist jedoch Ziel: möglichst wenige Behälter für alle Elemente zu finden.
Im Folgenden werden die Unterschiede zwischen den beiden Problemen zusammengefasst:
Mehrfaches Rucksackproblem: Verpacken Sie einen Teil der Artikel in eine feste Anzahl von mit unterschiedlichen Kapazitäten, sodass der Gesamtwert aller verpackten Artikel ist ein Höchstwert.
Problem beim Bepacken der Container: Bei so vielen Behältern mit der gleichen Kapazität wie nötig finden Sie die wenigsten, die alle Elemente enthalten. Bei dieser Aufgabe sind die Elemente werden keine Werte zugewiesen, weil das Ziel keinen Wert hat.
Das nächste Beispiel zeigt, wie ein Bin-Packing-Problem gelöst wird.
Beispiel
In diesem Beispiel müssen Artikel mit unterschiedlichen Gewichten in Behältern verpackt werden. mit einer gemeinsamen Kapazität. Angenommen, es gibt genug Behälter, besteht das Problem darin, möglichst wenige zu ermitteln.
In den folgenden Abschnitten werden Programme vorgestellt, die dieses Problem lösen. Für die vollständige finden Sie unter Programme abschließen.
In diesem Beispiel wird der MPSolver-Wrapper verwendet.
Bibliotheken importieren
Mit dem folgenden Code werden die erforderlichen Bibliotheken importiert.
Python
from ortools.linear_solver import pywraplp
C++
#include <iostream> #include <memory> #include <numeric> #include <ostream> #include <vector> #include "ortools/linear_solver/linear_expr.h" #include "ortools/linear_solver/linear_solver.h"
Java
import com.google.ortools.Loader; import com.google.ortools.linearsolver.MPConstraint; import com.google.ortools.linearsolver.MPObjective; import com.google.ortools.linearsolver.MPSolver; import com.google.ortools.linearsolver.MPVariable;
C#
using System; using Google.OrTools.LinearSolver;
Daten erstellen
Mit dem folgenden Code werden die Daten für das Beispiel erstellt.
Python
def create_data_model(): """Create the data for the example.""" data = {} weights = [48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30] data["weights"] = weights data["items"] = list(range(len(weights))) data["bins"] = data["items"] data["bin_capacity"] = 100 return data
C++
struct DataModel { const std::vector<double> weights = {48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30}; const int num_items = weights.size(); const int num_bins = weights.size(); const int bin_capacity = 100; };
Java
static class DataModel { public final double[] weights = {48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30}; public final int numItems = weights.length; public final int numBins = weights.length; public final int binCapacity = 100; }
C#
class DataModel { public static double[] Weights = { 48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30 }; public int NumItems = Weights.Length; public int NumBins = Weights.Length; public double BinCapacity = 100.0; }
Die Daten umfassen Folgendes:
weights
: Ein Vektor, der die Gewichtung der Elemente enthält.bin_capacity
: Eine einzelne Zahl, die die Kapazität der Container angibt.
Den Elementen sind keine Werte zugewiesen, da das Ziel, die Anzahl der Anzahl der Klassen hat keinen Wert.
Beachten Sie, dass num_bins
auf die Anzahl der Elemente festgelegt ist. Das liegt daran,
Problem eine Lösung hat, dann muss das Gewicht jedes Artikels kleiner oder gleich sein
mit der Behälterkapazität. In diesem Fall benötigen Sie maximal
die Anzahl der Artikel, da du jeden Artikel in einen separaten Container verschieben kannst.
Solverde deklarieren
Mit dem folgenden Code wird der Löser deklariert.
Python
# Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SCIP") if not solver: return
C++
// Create the mip solver with the SCIP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP")); if (!solver) { LOG(WARNING) << "SCIP solver unavailable."; return; }
Java
// Create the linear solver with the SCIP backend. MPSolver solver = MPSolver.createSolver("SCIP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; }
C#
// Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { return; }
Variablen erstellen
Mit dem folgenden Code werden die Variablen für das Programm erstellt.
Python
# Variables # x[i, j] = 1 if item i is packed in bin j. x = {} for i in data["items"]: for j in data["bins"]: x[(i, j)] = solver.IntVar(0, 1, "x_%i_%i" % (i, j)) # y[j] = 1 if bin j is used. y = {} for j in data["bins"]: y[j] = solver.IntVar(0, 1, "y[%i]" % j)
C++
std::vector<std::vector<const MPVariable*>> x( data.num_items, std::vector<const MPVariable*>(data.num_bins)); for (int i = 0; i < data.num_items; ++i) { for (int j = 0; j < data.num_bins; ++j) { x[i][j] = solver->MakeIntVar(0.0, 1.0, ""); } } // y[j] = 1 if bin j is used. std::vector<const MPVariable*> y(data.num_bins); for (int j = 0; j < data.num_bins; ++j) { y[j] = solver->MakeIntVar(0.0, 1.0, ""); }
Java
MPVariable[][] x = new MPVariable[data.numItems][data.numBins]; for (int i = 0; i < data.numItems; ++i) { for (int j = 0; j < data.numBins; ++j) { x[i][j] = solver.makeIntVar(0, 1, ""); } } MPVariable[] y = new MPVariable[data.numBins]; for (int j = 0; j < data.numBins; ++j) { y[j] = solver.makeIntVar(0, 1, ""); }
C#
Variable[,] x = new Variable[data.NumItems, data.NumBins]; for (int i = 0; i < data.NumItems; i++) { for (int j = 0; j < data.NumBins; j++) { x[i, j] = solver.MakeIntVar(0, 1, $"x_{i}_{j}"); } } Variable[] y = new Variable[data.NumBins]; for (int j = 0; j < data.NumBins; j++) { y[j] = solver.MakeIntVar(0, 1, $"y_{j}"); }
Wie im Beispiel mit mehreren Rucksäcken definieren Sie ein Array von Variablen x[(i,
j)]
, deren Wert 1 ist, wenn das Element i
in Container j
platziert wird, und andernfalls 0.
Für Bin-Packing definieren Sie auch ein Array von Variablen, y[j]
, mit dem Wert 1
wenn Container j
verwendet wird, d. h. wenn Gegenstände darin gepackt sind, und 0
sonst. Die Summe der y[j]
ergibt die Anzahl der verwendeten Klassen.
Einschränkungen definieren
Der folgende Code definiert die Einschränkungen für das Problem:
Python
# Constraints # Each item must be in exactly one bin. for i in data["items"]: solver.Add(sum(x[i, j] for j in data["bins"]) == 1) # The amount packed in each bin cannot exceed its capacity. for j in data["bins"]: solver.Add( sum(x[(i, j)] * data["weights"][i] for i in data["items"]) <= y[j] * data["bin_capacity"] )
C++
// Create the constraints. // Each item is in exactly one bin. for (int i = 0; i < data.num_items; ++i) { LinearExpr sum; for (int j = 0; j < data.num_bins; ++j) { sum += x[i][j]; } solver->MakeRowConstraint(sum == 1.0); } // For each bin that is used, the total packed weight can be at most // the bin capacity. for (int j = 0; j < data.num_bins; ++j) { LinearExpr weight; for (int i = 0; i < data.num_items; ++i) { weight += data.weights[i] * LinearExpr(x[i][j]); } solver->MakeRowConstraint(weight <= LinearExpr(y[j]) * data.bin_capacity); }
Java
double infinity = java.lang.Double.POSITIVE_INFINITY; for (int i = 0; i < data.numItems; ++i) { MPConstraint constraint = solver.makeConstraint(1, 1, ""); for (int j = 0; j < data.numBins; ++j) { constraint.setCoefficient(x[i][j], 1); } } // The bin capacity contraint for bin j is // sum_i w_i x_ij <= C*y_j // To define this constraint, first subtract the left side from the right to get // 0 <= C*y_j - sum_i w_i x_ij // // Note: Since sum_i w_i x_ij is positive (and y_j is 0 or 1), the right side must // be less than or equal to C. But it's not necessary to add this constraint // because it is forced by the other constraints. for (int j = 0; j < data.numBins; ++j) { MPConstraint constraint = solver.makeConstraint(0, infinity, ""); constraint.setCoefficient(y[j], data.binCapacity); for (int i = 0; i < data.numItems; ++i) { constraint.setCoefficient(x[i][j], -data.weights[i]); } }
C#
for (int i = 0; i < data.NumItems; ++i) { Constraint constraint = solver.MakeConstraint(1, 1, ""); for (int j = 0; j < data.NumBins; ++j) { constraint.SetCoefficient(x[i, j], 1); } } for (int j = 0; j < data.NumBins; ++j) { Constraint constraint = solver.MakeConstraint(0, Double.PositiveInfinity, ""); constraint.SetCoefficient(y[j], data.BinCapacity); for (int i = 0; i < data.NumItems; ++i) { constraint.SetCoefficient(x[i, j], -DataModel.Weights[i]); } }
Es gelten die folgenden Einschränkungen:
- Jeder Artikel muss genau einem Container zugeordnet werden. Diese Einschränkung wird durch
Dafür muss die Summe von
x[i][j]
über alle Klassenj
gleich 1 sein. Hinweis dass sich dies vom Problem mit mehreren Rucksacks unterscheidet, bei dem die Summe dürfen nur kleiner oder gleich 1 sein, da nicht alle Elemente gepackt werden kann. Das Gesamtgewicht in jedem Behälter darf seine Kapazität nicht überschreiten. Dies ist die die gleiche Einschränkung wie beim Problem mit mehreren Rucksäcken. In diesem Fall multiplizieren Sie die Bin-Kapazität auf der rechten Seite der Ungleichungen mit
y[j]
.Warum mit
y[j]
multiplizieren? Weil dadurchy[j]
erzwungen wird, dass der Wert 1 ist, wenn eines der Elemente im Behälterj
verpackt. Das liegt daran, dass beiy[j]
0 die rechte Seite von wäre die Ungleichung 0, während das Klassengewicht auf der linken Seite größer als 0 ist, was gegen die Beschränkung verstößt. Dadurch werden die Variableny[j]
zur Zielsetzung des Problems zu bringen. Fürs Erste versucht der Löser, Anzahl der Klassen, für diey[j]
1 ist.
Ziel definieren
Der folgende Code definiert die Zielfunktion für das Problem.
Python
# Objective: minimize the number of bins used. solver.Minimize(solver.Sum([y[j] for j in data["bins"]]))
C++
// Create the objective function. MPObjective* const objective = solver->MutableObjective(); LinearExpr num_bins_used; for (int j = 0; j < data.num_bins; ++j) { num_bins_used += y[j]; } objective->MinimizeLinearExpr(num_bins_used);
Java
MPObjective objective = solver.objective(); for (int j = 0; j < data.numBins; ++j) { objective.setCoefficient(y[j], 1); } objective.setMinimization();
C#
Objective objective = solver.Objective(); for (int j = 0; j < data.NumBins; ++j) { objective.SetCoefficient(y[j], 1); } objective.SetMinimization();
Da y[j]
bei Verwendung von bin j 1 ist und andernfalls 0, ist die Summe von y[j]
die Anzahl der verwendeten Container. Ziel ist es, die Summe zu minimieren.
Den Matherechner aufrufen und die Lösung ausdrucken
Mit dem folgenden Code wird der Matherechner aufgerufen und die Lösung ausgegeben.
Python
print(f"Solving with {solver.SolverVersion()}") status = solver.Solve() if status == pywraplp.Solver.OPTIMAL: num_bins = 0 for j in data["bins"]: if y[j].solution_value() == 1: bin_items = [] bin_weight = 0 for i in data["items"]: if x[i, j].solution_value() > 0: bin_items.append(i) bin_weight += data["weights"][i] if bin_items: num_bins += 1 print("Bin number", j) print(" Items packed:", bin_items) print(" Total weight:", bin_weight) print() print() print("Number of bins used:", num_bins) print("Time = ", solver.WallTime(), " milliseconds") else: print("The problem does not have an optimal solution.")
C++
const MPSolver::ResultStatus result_status = solver->Solve(); // Check that the problem has an optimal solution. if (result_status != MPSolver::OPTIMAL) { std::cerr << "The problem does not have an optimal solution!"; return; } std::cout << "Number of bins used: " << objective->Value() << std::endl << std::endl; double total_weight = 0; for (int j = 0; j < data.num_bins; ++j) { if (y[j]->solution_value() == 1) { std::cout << "Bin " << j << std::endl << std::endl; double bin_weight = 0; for (int i = 0; i < data.num_items; ++i) { if (x[i][j]->solution_value() == 1) { std::cout << "Item " << i << " - Weight: " << data.weights[i] << std::endl; bin_weight += data.weights[i]; } } std::cout << "Packed bin weight: " << bin_weight << std::endl << std::endl; total_weight += bin_weight; } } std::cout << "Total packed weight: " << total_weight << std::endl;
Java
final MPSolver.ResultStatus resultStatus = solver.solve(); // Check that the problem has an optimal solution. if (resultStatus == MPSolver.ResultStatus.OPTIMAL) { System.out.println("Number of bins used: " + objective.value()); double totalWeight = 0; for (int j = 0; j < data.numBins; ++j) { if (y[j].solutionValue() == 1) { System.out.println("\nBin " + j + "\n"); double binWeight = 0; for (int i = 0; i < data.numItems; ++i) { if (x[i][j].solutionValue() == 1) { System.out.println("Item " + i + " - weight: " + data.weights[i]); binWeight += data.weights[i]; } } System.out.println("Packed bin weight: " + binWeight); totalWeight += binWeight; } } System.out.println("\nTotal packed weight: " + totalWeight); } else { System.err.println("The problem does not have an optimal solution."); }
C#
Solver.ResultStatus resultStatus = solver.Solve(); // Check that the problem has an optimal solution. if (resultStatus != Solver.ResultStatus.OPTIMAL) { Console.WriteLine("The problem does not have an optimal solution!"); return; } Console.WriteLine($"Number of bins used: {solver.Objective().Value()}"); double TotalWeight = 0.0; for (int j = 0; j < data.NumBins; ++j) { double BinWeight = 0.0; if (y[j].SolutionValue() == 1) { Console.WriteLine($"Bin {j}"); for (int i = 0; i < data.NumItems; ++i) { if (x[i, j].SolutionValue() == 1) { Console.WriteLine($"Item {i} weight: {DataModel.Weights[i]}"); BinWeight += DataModel.Weights[i]; } } Console.WriteLine($"Packed bin weight: {BinWeight}"); TotalWeight += BinWeight; } } Console.WriteLine($"Total packed weight: {TotalWeight}");
Die Lösung zeigt die Mindestanzahl von Behältern, die zum Verpacken aller Artikel erforderlich sind. Die Lösung zeigt für jeden verwendeten Behälter die darin verpackten Artikel und die Gesamtgewicht der Container.
Ausgabe des Programms
Wenn Sie das Programm ausführen, wird die folgende Ausgabe angezeigt.
Bin number 0 Items packed: [1, 5, 10] Total weight: 87 Bin number 1 Items packed: [0, 6] Total weight: 90 Bin number 2 Items packed: [2, 4, 7] Total weight: 97 Bin number 3 Items packed: [3, 8, 9] Total weight: 96 Number of bins used: 4.0
Programme abschließen
Die Programme für das Behälter-Packen sind unten aufgeführt.
Python
from ortools.linear_solver import pywraplp def create_data_model(): """Create the data for the example.""" data = {} weights = [48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30] data["weights"] = weights data["items"] = list(range(len(weights))) data["bins"] = data["items"] data["bin_capacity"] = 100 return data def main(): data = create_data_model() # Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SCIP") if not solver: return # Variables # x[i, j] = 1 if item i is packed in bin j. x = {} for i in data["items"]: for j in data["bins"]: x[(i, j)] = solver.IntVar(0, 1, "x_%i_%i" % (i, j)) # y[j] = 1 if bin j is used. y = {} for j in data["bins"]: y[j] = solver.IntVar(0, 1, "y[%i]" % j) # Constraints # Each item must be in exactly one bin. for i in data["items"]: solver.Add(sum(x[i, j] for j in data["bins"]) == 1) # The amount packed in each bin cannot exceed its capacity. for j in data["bins"]: solver.Add( sum(x[(i, j)] * data["weights"][i] for i in data["items"]) <= y[j] * data["bin_capacity"] ) # Objective: minimize the number of bins used. solver.Minimize(solver.Sum([y[j] for j in data["bins"]])) print(f"Solving with {solver.SolverVersion()}") status = solver.Solve() if status == pywraplp.Solver.OPTIMAL: num_bins = 0 for j in data["bins"]: if y[j].solution_value() == 1: bin_items = [] bin_weight = 0 for i in data["items"]: if x[i, j].solution_value() > 0: bin_items.append(i) bin_weight += data["weights"][i] if bin_items: num_bins += 1 print("Bin number", j) print(" Items packed:", bin_items) print(" Total weight:", bin_weight) print() print() print("Number of bins used:", num_bins) print("Time = ", solver.WallTime(), " milliseconds") else: print("The problem does not have an optimal solution.") if __name__ == "__main__": main()
C++
#include <iostream> #include <memory> #include <numeric> #include <ostream> #include <vector> #include "ortools/linear_solver/linear_expr.h" #include "ortools/linear_solver/linear_solver.h" namespace operations_research { struct DataModel { const std::vector<double> weights = {48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30}; const int num_items = weights.size(); const int num_bins = weights.size(); const int bin_capacity = 100; }; void BinPackingMip() { DataModel data; // Create the mip solver with the SCIP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP")); if (!solver) { LOG(WARNING) << "SCIP solver unavailable."; return; } std::vector<std::vector<const MPVariable*>> x( data.num_items, std::vector<const MPVariable*>(data.num_bins)); for (int i = 0; i < data.num_items; ++i) { for (int j = 0; j < data.num_bins; ++j) { x[i][j] = solver->MakeIntVar(0.0, 1.0, ""); } } // y[j] = 1 if bin j is used. std::vector<const MPVariable*> y(data.num_bins); for (int j = 0; j < data.num_bins; ++j) { y[j] = solver->MakeIntVar(0.0, 1.0, ""); } // Create the constraints. // Each item is in exactly one bin. for (int i = 0; i < data.num_items; ++i) { LinearExpr sum; for (int j = 0; j < data.num_bins; ++j) { sum += x[i][j]; } solver->MakeRowConstraint(sum == 1.0); } // For each bin that is used, the total packed weight can be at most // the bin capacity. for (int j = 0; j < data.num_bins; ++j) { LinearExpr weight; for (int i = 0; i < data.num_items; ++i) { weight += data.weights[i] * LinearExpr(x[i][j]); } solver->MakeRowConstraint(weight <= LinearExpr(y[j]) * data.bin_capacity); } // Create the objective function. MPObjective* const objective = solver->MutableObjective(); LinearExpr num_bins_used; for (int j = 0; j < data.num_bins; ++j) { num_bins_used += y[j]; } objective->MinimizeLinearExpr(num_bins_used); const MPSolver::ResultStatus result_status = solver->Solve(); // Check that the problem has an optimal solution. if (result_status != MPSolver::OPTIMAL) { std::cerr << "The problem does not have an optimal solution!"; return; } std::cout << "Number of bins used: " << objective->Value() << std::endl << std::endl; double total_weight = 0; for (int j = 0; j < data.num_bins; ++j) { if (y[j]->solution_value() == 1) { std::cout << "Bin " << j << std::endl << std::endl; double bin_weight = 0; for (int i = 0; i < data.num_items; ++i) { if (x[i][j]->solution_value() == 1) { std::cout << "Item " << i << " - Weight: " << data.weights[i] << std::endl; bin_weight += data.weights[i]; } } std::cout << "Packed bin weight: " << bin_weight << std::endl << std::endl; total_weight += bin_weight; } } std::cout << "Total packed weight: " << total_weight << std::endl; } } // namespace operations_research int main(int argc, char** argv) { operations_research::BinPackingMip(); return EXIT_SUCCESS; }
Java
package com.google.ortools.linearsolver.samples; import com.google.ortools.Loader; import com.google.ortools.linearsolver.MPConstraint; import com.google.ortools.linearsolver.MPObjective; import com.google.ortools.linearsolver.MPSolver; import com.google.ortools.linearsolver.MPVariable; /** Bin packing problem. */ public class BinPackingMip { static class DataModel { public final double[] weights = {48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30}; public final int numItems = weights.length; public final int numBins = weights.length; public final int binCapacity = 100; } public static void main(String[] args) throws Exception { Loader.loadNativeLibraries(); final DataModel data = new DataModel(); // Create the linear solver with the SCIP backend. MPSolver solver = MPSolver.createSolver("SCIP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; } MPVariable[][] x = new MPVariable[data.numItems][data.numBins]; for (int i = 0; i < data.numItems; ++i) { for (int j = 0; j < data.numBins; ++j) { x[i][j] = solver.makeIntVar(0, 1, ""); } } MPVariable[] y = new MPVariable[data.numBins]; for (int j = 0; j < data.numBins; ++j) { y[j] = solver.makeIntVar(0, 1, ""); } double infinity = java.lang.Double.POSITIVE_INFINITY; for (int i = 0; i < data.numItems; ++i) { MPConstraint constraint = solver.makeConstraint(1, 1, ""); for (int j = 0; j < data.numBins; ++j) { constraint.setCoefficient(x[i][j], 1); } } // The bin capacity contraint for bin j is // sum_i w_i x_ij <= C*y_j // To define this constraint, first subtract the left side from the right to get // 0 <= C*y_j - sum_i w_i x_ij // // Note: Since sum_i w_i x_ij is positive (and y_j is 0 or 1), the right side must // be less than or equal to C. But it's not necessary to add this constraint // because it is forced by the other constraints. for (int j = 0; j < data.numBins; ++j) { MPConstraint constraint = solver.makeConstraint(0, infinity, ""); constraint.setCoefficient(y[j], data.binCapacity); for (int i = 0; i < data.numItems; ++i) { constraint.setCoefficient(x[i][j], -data.weights[i]); } } MPObjective objective = solver.objective(); for (int j = 0; j < data.numBins; ++j) { objective.setCoefficient(y[j], 1); } objective.setMinimization(); final MPSolver.ResultStatus resultStatus = solver.solve(); // Check that the problem has an optimal solution. if (resultStatus == MPSolver.ResultStatus.OPTIMAL) { System.out.println("Number of bins used: " + objective.value()); double totalWeight = 0; for (int j = 0; j < data.numBins; ++j) { if (y[j].solutionValue() == 1) { System.out.println("\nBin " + j + "\n"); double binWeight = 0; for (int i = 0; i < data.numItems; ++i) { if (x[i][j].solutionValue() == 1) { System.out.println("Item " + i + " - weight: " + data.weights[i]); binWeight += data.weights[i]; } } System.out.println("Packed bin weight: " + binWeight); totalWeight += binWeight; } } System.out.println("\nTotal packed weight: " + totalWeight); } else { System.err.println("The problem does not have an optimal solution."); } } private BinPackingMip() {} }
C#
using System; using Google.OrTools.LinearSolver; public class BinPackingMip { class DataModel { public static double[] Weights = { 48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30 }; public int NumItems = Weights.Length; public int NumBins = Weights.Length; public double BinCapacity = 100.0; } public static void Main() { DataModel data = new DataModel(); // Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { return; } Variable[,] x = new Variable[data.NumItems, data.NumBins]; for (int i = 0; i < data.NumItems; i++) { for (int j = 0; j < data.NumBins; j++) { x[i, j] = solver.MakeIntVar(0, 1, $"x_{i}_{j}"); } } Variable[] y = new Variable[data.NumBins]; for (int j = 0; j < data.NumBins; j++) { y[j] = solver.MakeIntVar(0, 1, $"y_{j}"); } for (int i = 0; i < data.NumItems; ++i) { Constraint constraint = solver.MakeConstraint(1, 1, ""); for (int j = 0; j < data.NumBins; ++j) { constraint.SetCoefficient(x[i, j], 1); } } for (int j = 0; j < data.NumBins; ++j) { Constraint constraint = solver.MakeConstraint(0, Double.PositiveInfinity, ""); constraint.SetCoefficient(y[j], data.BinCapacity); for (int i = 0; i < data.NumItems; ++i) { constraint.SetCoefficient(x[i, j], -DataModel.Weights[i]); } } Objective objective = solver.Objective(); for (int j = 0; j < data.NumBins; ++j) { objective.SetCoefficient(y[j], 1); } objective.SetMinimization(); Solver.ResultStatus resultStatus = solver.Solve(); // Check that the problem has an optimal solution. if (resultStatus != Solver.ResultStatus.OPTIMAL) { Console.WriteLine("The problem does not have an optimal solution!"); return; } Console.WriteLine($"Number of bins used: {solver.Objective().Value()}"); double TotalWeight = 0.0; for (int j = 0; j < data.NumBins; ++j) { double BinWeight = 0.0; if (y[j].SolutionValue() == 1) { Console.WriteLine($"Bin {j}"); for (int i = 0; i < data.NumItems; ++i) { if (x[i, j].SolutionValue() == 1) { Console.WriteLine($"Item {i} weight: {DataModel.Weights[i]}"); BinWeight += DataModel.Weights[i]; } } Console.WriteLine($"Packed bin weight: {BinWeight}"); TotalWeight += BinWeight; } } Console.WriteLine($"Total packed weight: {TotalWeight}"); } }