Как и задача о нескольких рюкзаках, задача об упаковке корзин также включает в себя упаковку предметов в корзины. Однако задача упаковки корзин преследует другую цель: найти наименьшее количество корзин, в которых поместятся все предметы.
Ниже суммированы различия между двумя проблемами:
Задача с несколькими рюкзаками: упакуйте подмножество предметов в фиксированное количество контейнеров различной вместимости так, чтобы общая стоимость упакованных предметов была максимальной.
Задача с упаковкой корзин: учитывая необходимое количество корзин одинаковой вместимости, найдите наименьшее количество, в которое поместятся все предметы. В этой задаче элементам не присваиваются значения, поскольку цель не предполагает ценности.
В следующем примере показано, как решить проблему упаковки контейнеров.
Пример
В этом примере предметы разного веса необходимо упаковать в набор контейнеров общей вместимости. Если предположить, что контейнеров достаточно, чтобы вместить все предметы, проблема состоит в том, чтобы найти наименьшее количество, которого будет достаточно.
В следующих разделах представлены программы, решающие эту проблему. Полные программы см. в разделе Полные программы .
В этом примере используется оболочка MPsolver .
Импортируйте библиотеки
Код ниже импортирует необходимые библиотеки.
Питон
from ortools.linear_solver import pywraplp
С++
#include <iostream> #include <memory> #include <numeric> #include <ostream> #include <vector> #include "ortools/linear_solver/linear_expr.h" #include "ortools/linear_solver/linear_solver.h"
Ява
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;
С#
using System; using Google.OrTools.LinearSolver;
Создайте данные
Код ниже создает данные для примера.
Питон
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
С++
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; };
Ява
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; }
С#
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; }
Данные включают в себя следующее:
-
weights
: вектор, содержащий веса элементов. -
bin_capacity
: одно число, указывающее вместимость бункеров.
Элементам не присваиваются никакие значения, поскольку цель минимизации количества ячеек не связана с ценностью.
Обратите внимание, что для num_bins
установлено количество элементов. Это связано с тем, что если проблема имеет решение, то вес каждого предмета должен быть меньше или равен вместимости контейнера. В этом случае максимальное количество корзин, которое вам может понадобиться, равно количеству предметов, поскольку вы всегда можете поместить каждый предмет в отдельную корзину.
Объявить решатель
Следующий код объявляет решатель.
Питон
# Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SCIP") if not solver: return
С++
// Create the mip solver with the SCIP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP")); if (!solver) { LOG(WARNING) << "SCIP solver unavailable."; return; }
Ява
// 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; }
С#
// Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { 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)
С++
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, ""); }
Ява
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, ""); }
С#
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}"); }
Как и в примере с несколькими рюкзаками, вы определяете массив переменных x[(i, j)]
, значение которых равно 1, если элемент i
помещен в корзину j
, и 0 в противном случае.
Для упаковки контейнеров вы также определяете массив переменных y[j]
, значение которого равно 1, если используется контейнер j
, то есть, если в него упакованы какие-либо элементы, и 0 в противном случае. Сумма y[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"] )
С++
// 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); }
Ява
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]); } }
С#
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]); } }
Ограничения следующие:
- Каждый предмет должен быть помещен ровно в одну корзину. Это ограничение устанавливается требованием, чтобы сумма
x[i][j]
по всем контейнерамj
была равна 1. Обратите внимание, что это отличается от задачи о множественном рюкзаке, в которой требуется, чтобы сумма была меньше или равна 1, потому что не все предметы должны быть упакованы. Общий вес каждого контейнера не может превышать его вместимость. Это то же ограничение, что и в задаче о нескольких рюкзаках, но в этом случае вы умножаете емкость контейнера в правой части неравенства на
y[j]
.Зачем умножать на
y[j]
? Потому что это заставляетy[j]
равняться 1, если какой-либо элемент упакован в корзинуj
. Это так, потому что, если быy[j]
было 0, правая часть неравенства была бы 0, а вес ячейки в левой части был бы больше 0, что нарушает ограничение. Это связывает переменныеy[j]
с целью задачи, поскольку теперь решатель попытается минимизировать количество интервалов, для которыхy[j]
равно 1.
Определите цель
Следующий код определяет целевую функцию для задачи.
Питон
# Objective: minimize the number of bins used. solver.Minimize(solver.Sum([y[j] for j in data["bins"]]))
С++
// 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);
Ява
MPObjective objective = solver.objective(); for (int j = 0; j < data.numBins; ++j) { objective.setCoefficient(y[j], 1); } objective.setMinimization();
С#
Objective objective = solver.Objective(); for (int j = 0; j < data.NumBins; ++j) { objective.SetCoefficient(y[j], 1); } objective.SetMinimization();
Поскольку y[j]
равен 1, если используется элемент j, и 0 в противном случае, сумма y[j]
представляет собой количество используемых ячеек. Цель – минимизировать сумму.
Вызовите решатель и распечатайте решение
Следующий код вызывает решатель и печатает решение.
Питон
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.")
С++
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;
Ява
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."); }
С#
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}");
Решение показывает минимальное количество контейнеров, необходимое для упаковки всех предметов. Для каждой используемой корзины решение показывает упакованные в нее предметы и общий вес корзины.
Вывод программы
Когда вы запускаете программу, она отображает следующий вывод.
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
Полные программы
Полные программы для решения задачи упаковки мусорных баков показаны ниже.
Питон
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()
С++
#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; }
Ява
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() {} }
С#
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}"); } }