Assim como o problema de várias mochilas, o problema de empacotamento também envolve ao embalar itens em latas. No entanto, o problema de empacotamento tem um Objetivo: encontrar o menor número de caixas que vão conter todos os itens.
Veja a seguir um resumo das diferenças entre os dois problemas:
Problema com várias mochilas: embale um subconjunto dos itens em um número fixo de com capacidades variadas, de modo que o valor total dos itens embalados máximo.
Problema de empacotamento: considerando quantos recipientes tiverem uma capacidade comum conforme necessário, encontrar o menor número que vai conter todos os itens. Neste problema, os itens não recebem valores, porque o objetivo não envolve valor.
O próximo exemplo mostra como resolver um problema de empacotamento.
Exemplo
Neste exemplo, itens com pesos variados precisam ser embalados em um conjunto de caixas com uma capacidade comum. Supondo que há agrupamentos suficientes para conter todas as itens, o problema é encontrar o mínimo que será suficiente.
As seções a seguir apresentam programas que resolvem esse problema. Para o programas, consulte Concluir programas.
Este exemplo usa o wrapper MPSolver.
Importar as bibliotecas
O código abaixo importa as bibliotecas necessárias.
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;
Criar os dados
O código abaixo cria os dados para o exemplo.
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; }
Os dados incluem o seguinte:
weights
: um vetor que contém os pesos dos itens.bin_capacity
: um único número que fornece a capacidade dos agrupamentos.
Não há valores atribuídos aos itens porque o objetivo de minimizar o o número de agrupamentos não envolve valor.
Observe que num_bins
é definido como o número de itens. Isso ocorre porque, se o
tem uma solução, então o peso de cada item deve ser menor ou igual
à capacidade do compartimento. Nesse caso, o número máximo de agrupamentos que você pode precisar é
o número de itens, porque sempre é possível colocar cada item em uma lixeira separada.
Declarar o solucionador
O código a seguir declara o solucionador.
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; }
Criar as variáveis
O código a seguir cria as variáveis para o programa.
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}"); }
Como no exemplo de várias mochilas, você define uma matriz de variáveis x[(i,
j)]
, cujo valor será 1 se o item i
for colocado no agrupamento j
; caso contrário, será 0.
Para empacotamento, você também define uma matriz de variáveis, y[j]
, com valor 1.
se o agrupamento j
for usado, ou seja, se algum item estiver dentro dele, e 0
caso contrário. A soma de y[j]
será o número de agrupamentos usados.
Definir as restrições
O código a seguir define as restrições do problema:
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]); } }
As restrições são as seguintes:
- Cada item precisa ser colocado em uma lixeira. Essa restrição é definida pela
exigindo que a soma de
x[i][j]
em todos os agrupamentos por classesj
seja igual a 1. Observação que isso é diferente do problema de múltiplas mochilas, em que a soma é precisa ser menor ou igual a 1, porque nem todos os itens precisam ser embalados. O peso total embalado em cada recipiente não pode exceder a capacidade dele. Esta é a mesma restrição do problema de múltiplas mochilas, mas nesse caso você multiplique a capacidade do agrupamento no lado direito das inequações por
y[j]
.Por que multiplicar por
y[j]
? Como isso forçay[j]
a ser igual a 1 se algum item for embalado na caixaj
. Isso ocorre porque, sey[j]
fosse 0, o lado direito do a desigualdade seria 0, enquanto o peso do agrupamento no lado esquerdo seria maior do que 0, violando a restrição. Isso conecta as variáveisy[j]
ao objetivo do problema, por enquanto o solucionador tentará minimizar a número de agrupamentos em quey[j]
é 1.
Defina o objetivo
O código a seguir define a função objetiva do problema.
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();
Como y[j]
é 1 se o agrupamento por classes for usado, e 0 em outros casos, a soma de y[j]
será
o número de agrupamentos usados. O objetivo é minimizar a soma.
Chamar o solucionador e imprimir a solução
O código a seguir chama o solucionador e exibe a solução.
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}");
A solução mostra o número mínimo de caixas necessárias para embalar todos os itens. Para cada recipiente usado, a solução mostra os itens embalados nele e as peso total do compartimento.
Saída do programa
Quando você executa o programa, ele mostra a seguinte saída:
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
Programas completos
Os programas completos para o problema de empacotamento são mostrados abaixo.
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}"); } }