बिन पैक करने की समस्या

मल्टीपल नैपसैक की समस्या की तरह ही, बिन पैकिंग की समस्या में भी आइटम को बिन में पैक करने की सुविधा. हालांकि, बिन पैकिंग की समस्या कुछ अलग है मकसद: ऐसे कम से कम बिन ढूंढें जिनमें सभी आइटम रखे हों.

नीचे दिया गया है कि दोनों समस्याओं के बीच के अंतर क्या हैं:

  • मल्टीपल नैपसैक की समस्या: आइटम के सबसेट को तय संख्या में पैक करना अलग-अलग क्षमता वाले बिन, ताकि पैक किए गए आइटम की कुल कीमत बताई जा सके अधिकतम है.

  • बिन को पैक करने की समस्या: ज़रूरत के हिसाब से समान क्षमता वाले कई बिन होने पर, वह सबसे कम खोजें जिसमें सभी आइटम होंगे. इस समस्या में, आइटम वैल्यू असाइन नहीं की जातीं, क्योंकि मकसद में वैल्यू शामिल नहीं होती.

अगला उदाहरण दिखाता है कि बिन पैकिंग की समस्या को कैसे हल किया जाए.

उदाहरण

इस उदाहरण में, अलग-अलग वज़न वाले आइटम को बिन में पैक किया जाना चाहिए उनकी क्षमता बढ़ जाती है. यह मानकर कि हर बिन में सामान रखने के लिए काफ़ी बिन हैं आइटम हैं, तो समस्या कम से कम उस आइटम को खोजने की है जो काफ़ी हो.

नीचे दिए गए सेक्शन में, इस समस्या को हल करने वाले प्रोग्राम दिए गए हैं. पूरे प्रोग्राम में, पूरा प्रोग्राम देखें.

इस उदाहरण में MPSolver रैपर का इस्तेमाल किया गया है.

लाइब्रेरी इंपोर्ट करें

नीचे दिया गया कोड ज़रूरी लाइब्रेरी को इंपोर्ट करता है.

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;

डेटा बनाना

नीचे दिया गया कोड, उदाहरण के लिए डेटा बनाता है.

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;
}

डेटा में ये चीज़ें शामिल होती हैं:

  • weights: आइटम का वज़न बताने वाला वेक्टर.
  • bin_capacity: बिन की क्षमता बताने वाली एक संख्या.

आइटम को कोई मान असाइन नहीं किया गया है, क्योंकि बिन की संख्या में वैल्यू शामिल नहीं होती.

ध्यान दें कि num_bins को आइटम की संख्या पर सेट किया गया है. ऐसा इसलिए होता है, क्योंकि अगर समस्या का एक हल है, तो हर आइटम का वज़न इससे कम या उसके बराबर होना चाहिए बिन की कपैसिटी तक बढ़ाएं. इस स्थिति में, आपको ज़्यादा से ज़्यादा बिन की ज़रूरत पड़ सकती है आइटम की संख्या बढ़ा सकते हैं, क्योंकि हर आइटम को अलग बिन में रखा जा सकता है.

सॉल्वर के बारे में बताओ

यहां दिया गया कोड, सॉल्वर के बारे में बताता है.

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;
      }

वैरिएबल बनाना

यह कोड, प्रोग्राम के लिए वैरिएबल बनाता है.

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}");
}

जैसे कि एक से ज़्यादा नैपसेक के उदाहरण में, आपने वैरिएबल x[(i, j)] का अरे तय किया है. अगर आइटम i को बिन j में रखा गया है, तो उसकी वैल्यू 1 होगी, नहीं तो 0 होगी.

बिन पैकिंग के लिए, वैरिएबल का कलेक्शन y[j] भी तय किया जाता है, जिसकी वैल्यू 1 होती है अगर बिन j का इस्तेमाल किया गया है, तो इसका मतलब है कि उसमें कोई सामान पैक किया गया है. इसके अलावा, 0 नहीं तो. y[j] का योग, इस्तेमाल किए गए बिन की संख्या होगी.

सीमाएं तय करना

यह कोड समस्या की सीमाओं के बारे में बताता है:

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]);
    }
}

शर्तें नीचे दी गई हैं:

  • हर आइटम को सिर्फ़ एक बिन में रखना चाहिए. यह कंस्ट्रेंट इसे सेट करता है: यह ज़रूरी है कि सभी बिन में x[i][j] का योग j हो. नोट जोड़ें यह एक से ज़्यादा नैपैक की समस्या से अलग है. इन समस्याओं का कुल योग, सिर्फ़ 1 से कम या उसके बराबर होना ज़रूरी है, क्योंकि सभी आइटम के लिए पैक होना चाहिए.
  • हर बिन में पैक किया गया कुल वज़न इसकी क्षमता से ज़्यादा नहीं हो सकता. यह है कंस्ट्रेंट जैसा कि एक से ज़्यादा नैपसैक की समस्या में होता है, लेकिन इस मामले में आपको इनइक्वालिटी की दाईं ओर मौजूद बिन की क्षमता को y[j] से गुणा करें.

    y[j] से गुणा क्यों करें? क्योंकि यह y[j] को 1 के बराबर होने के लिए मजबूर करता है, अगर कोई आइटम j को बिन में पैक किया गया. ऐसा इसलिए है, क्योंकि अगर y[j] 0 थी, तो असमानता 0 होगी, जबकि बाईं ओर के बिन का वज़न 0 से ज़्यादा, कंस्ट्रेंट का उल्लंघन करता है. इससे y[j] वैरिएबल कनेक्ट हो जाते हैं अब सॉल्वर समस्या को कम करने की कोशिश करेगा बिन की संख्या, जिसके लिए y[j], 1 है.

मकसद तय करना

नीचे दिया गया कोड, सवाल के मकसद के लिए फ़ंक्शन को तय करता है.

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();

अगर बिन j का इस्तेमाल किया जाता है, तो y[j] की वैल्यू 1 होती है और अगर 0 नहीं होती है, तो y[j] का योग होता है इस्तेमाल किए गए बिन की संख्या. इसका मकसद कुल वैल्यू को कम करना है.

सॉल्वर को कॉल करें और समाधान को प्रिंट करें

यहां दिया गया कोड, सॉल्वर को कॉल करता है और समाधान को प्रिंट करता है.

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}");

सलूशन से पता चलता है कि सभी सामान को पैक करने के लिए कम से कम कितने बिन ज़रूरी हैं. इस्तेमाल होने वाली हर बिन के लिए, घोल उसमें पैक किए गए आइटम दिखाता है. बिन का कुल वज़न.

प्रोग्राम का आउटपुट

प्रोग्राम को चलाने पर, यह नीचे दिया गया आउटपुट दिखाता है.

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

प्रोग्राम पूरे करें

बिन पैकिंग की समस्या हल करने के तरीके यहां बताए गए हैं.

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}");
    }
}