Проблема диеты Стиглера

В этом разделе мы покажем, как решить классическую проблему, называемую диетой Стиглера , названной в честь лауреата Нобелевской премии по экономике Джорджа Стиглера, который рассчитал недорогой способ удовлетворения основных потребностей в питании при наличии набора продуктов. Он представил это как математическое упражнение, а не как рекомендации по питанию, хотя идея расчета оптимального питания недавно вошла в моду .

Диета Стиглера требовала соблюдения этих минимумов:

Список питательных веществ

Питательное вещество Рекомендуемая суточная доза
Калории 3000 калорий
Белок 70 грамм
Кальций 0,8 грамма
Железо 12 миллиграмм
Витамин А 5000 МЕ
Тиамин (витамин B1) 1,8 миллиграммы
Рибофлавин (витамин B2) 2,7 миллиграмма
Ниацин 18 миллиграмм
Аскорбиновая кислота (витамин С) 75 миллиграмм

Набор продуктов, которые оценивал Стиглер, был отражением времени (1944 г.). Приведенные ниже данные о питательной ценности приведены на доллар, а не на единицу, поэтому цель состоит в том, чтобы определить, сколько долларов потратить на каждый продукт.

Список товаров

Товар Единица Цена 1939 года (центов) Калории (ккал) Белок (г) Кальций (г) Железо (мг) Витамин А (КИУ) Тиамин (мг) Рибофлавин (мг) Ниацин (мг) Аскорбиновая кислота (мг)
Пшеничная мука (обогащенная) 10 фунтов. 36 44,7 1411 2 365 0 55,4 33,3 441 0
Макароны 1 фунт. 14.1 11,6 418 0,7 54 0 3.2 1,9 68 0
Пшеничные хлопья (обогащенные) 28 унций. 24.2 11,8 377 14,4 175 0 14,4 8,8 114 0
Кукурузные хлопья 8 унций. 7.1 11.4 252 0,1 56 0 13,5 2.3 68 0
Кукурузная мука 1 фунт. 4.6 36,0 897 1,7 99 30,9 17,4 7,9 106 0
Мамалыга крупа 24 унции. 8,5 28,6 680 0,8 80 0 10,6 1,6 110 0
Рис 1 фунт. 7,5 21.2 460 0,6 41 0 2 4,8 60 0
Овсяные хлопья 1 фунт. 7.1 25,3 907 5.1 341 0 37,1 8,9 64 0
Белый Хлеб (обогащенный) 1 фунт. 7,9 15,0 488 2,5 115 0 13,8 8,5 126 0
Цельнозерновой хлеб 1 фунт. 9.1 12.2 484 2,7 125 0 13,9 6.4 160 0
Ржаной хлеб 1 фунт. 9.1 12.4 439 1.1 82 0 9,9 3 66 0
Фунтовый пирог 1 фунт. 24,8 8.0 130 0,4 31 18,9 2,8 3 17 0
Содовые крекеры 1 фунт. 15.1 12,5 288 0,5 50 0 0 0 0 0
Молоко 1 кварта. 11 6.1 310 10,5 18 16,8 4 16 7 177
Сгущенное молоко (банка) 14,5 унций. 6,7 8.4 422 15.1 9 26 3 23,5 11 60
Масло 1 фунт. 30,8 10,8 9 0,2 3 44,2 0 0,2 2 0
Олеомаргарин 1 фунт. 16.1 20,6 17 0,6 6 55,8 0,2 0 0 0
Яйца 1 доза. 32,6 2,9 238 1.0 52 18,6 2,8 6,5 1 0
Сыр (Чеддер) 1 фунт. 24.2 7.4 448 16,4 19 28,1 0,8 10.3 4 0
Крем 1/2 пт. 14.1 3,5 49 1,7 3 16,9 0,6 2,5 0 17
Арахисовое масло 1 фунт. 17,9 15,7 661 1.0 48 0 9,6 8.1 471 0
Майонез 1/2 пт. 16,7 8,6 18 0,2 8 2,7 0,4 0,5 0 0
Криско 1 фунт. 20.3 20.1 0 0 0 0 0 0 0 0
Сало 1 фунт. 9,8 41,7 0 0 0 0,2 0 0,5 5 0
Стейк без костей 1 фунт. 39,6 2,9 166 0,1 34 0,2 2.1 2,9 69 0
Круглый стейк 1 фунт. 36,4 2.2 214 0,1 32 0,4 2,5 2.4 87 0
Жаркое из ребрышек 1 фунт. 29,2 3.4 213 0,1 33 0 0 2 0 0
Чак Рост 1 фунт. 22,6 3.6 309 0,2 46 0,4 1 4 120 0
Тарелка 1 фунт. 14,6 8,5 404 0,2 62 0 0,9 0 0 0
Печень (говяжья) 1 фунт. 26,8 2.2 333 0,2 139 169,2 6.4 50,8 316 525
Баранья нога 1 фунт. 27,6 3.1 245 0,1 20 0 2,8 3,9 86 0
Бараньи отбивные (ребрышки) 1 фунт. 36,6 3.3 140 0,1 15 0 1,7 2,7 54 0
Свиные отбивные 1 фунт. 30,7 3,5 196 0,2 30 0 17,4 2,7 60 0
Жареная свиная корейка 1 фунт. 24.2 4.4 249 0,3 37 0 18.2 3.6 79 0
Бекон 1 фунт. 25,6 10.4 152 0,2 23 0 1,8 1,8 71 0
Ветчина, копченая 1 фунт. 27,4 6,7 212 0,2 31 0 9,9 3.3 50 0
Соленая свинина 1 фунт. 16 18,8 164 0,1 26 0 1,4 1,8 0 0
Жареная курица 1 фунт. 30,3 1,8 184 0,1 30 0,1 0,9 1,8 68 46
Котлеты из телятины 1 фунт. 42,3 1,7 156 0,1 24 0 1,4 2.4 57 0
Лосось, Розовый (банка) 16 унций. 13 5,8 705 6,8 45 3,5 1 4,9 209 0
Яблоки 1 фунт. 4.4 5,8 27 0,5 36 7.3 3.6 2,7 5 544
Бананы 1 фунт. 6.1 4,9 60 0,4 30 17,4 2,5 3,5 28 498
Лимоны 1 доза. 26 1.0 21 0,5 14 0 0,5 0 4 952
Апельсины 1 доза. 30,9 2.2 40 1.1 18 11.1 3.6 1.3 10 1998 год
Зеленая фасоль 1 фунт. 7.1 2.4 138 3.7 80 69 4.3 5,8 37 862
Капуста 1 фунт. 3.7 2.6 125 4.0 36 7.2 9 4,5 26 5369
Морковь 1 пучок 4.7 2,7 73 2,8 43 188,5 6.1 4.3 89 608
Сельдерей 1 стебель 7.3 0,9 51 3.0 23 0,9 1,4 1,4 9 313
Латук 1 голова 8.2 0,4 27 1.1 22 112,4 1,8 3.4 11 449
Лук 1 фунт. 3.6 5,8 166 3,8 59 16,6 4.7 5,9 21 1184
Картофель 15 фунтов. 34 14.3 336 1,8 118 6,7 29,4 7.1 198 2522
Шпинат 1 фунт. 8.1 1.1 106 0 138 918,4 5,7 13,8 33 2755
Сладкий картофель 1 фунт. 5.1 9,6 138 2,7 54 290,7 8.4 5.4 83 1912 год
Персики (банка) № 2 1/2 16,8 3.7 20 0,4 10 21,5 0,5 1 31 196
Груши (можно) № 2 1/2 20,4 3.0 8 0,3 8 0,8 0,8 0,8 5 81
Ананас (банка) № 2 1/2 21,3 2.4 16 0,4 8 2 2,8 0,8 7 399
Спаржа (можно) № 2 27,7 0,4 33 0,3 12 16.3 1,4 2.1 17 272
Зеленая фасоль (банка) № 2 10 1.0 54 2 65 53,9 1,6 4.3 32 431
Свинина и фасоль (банка) 16 унций. 7.1 7,5 364 4 134 3,5 8.3 7,7 56 0
Кукуруза (банка) № 2 10.4 5.2 136 0,2 16 12 1,6 2,7 42 218
Горох (банка) № 2 13,8 2.3 136 0,6 45 34,9 4,9 2,5 37 370
Помидоры (банка) № 2 8,6 1.3 63 0,7 38 53,2 3.4 2,5 36 1253
Томатный суп (банка) 10 1/2 унции. 7,6 1,6 71 0,6 43 57,9 3,5 2.4 67 862
Персики сушеные 1 фунт. 15,7 8,5 87 1,7 173 86,8 1.2 4.3 55 57
Чернослив сушеный 1 фунт. 9 12,8 99 2,5 154 85,7 3,9 4.3 65 257
Изюм сушеный 15 унций. 9.4 13,5 104 2,5 136 4,5 6.3 1,4 24 136
Горох сушеный 1 фунт. 7,9 20,0 1367 4.2 345 2,9 28,7 18,4 162 0
Лимская фасоль, сушеная 1 фунт. 8,9 17,4 1055 3.7 459 5.1 26,9 38,2 93 0
Фасоль темно-синяя, сушеная 1 фунт. 5,9 26,9 1691 г. 11.4 792 0 38,4 24,6 217 0
Кофе 1 фунт. 22,4 0 0 0 0 0 4 5.1 50 0
Чай 1/4 фунта. 17,4 0 0 0 0 0 0 2.3 42 0
Какао 8 унций. 8,6 8,7 237 3 72 0 2 11,9 40 0
Шоколад 8 унций. 16.2 8.0 77 1.3 39 0 0,9 3.4 14 0
Сахар 10 фунтов. 51,7 34,9 0 0 0 0 0 0 0 0
Кукурузный сироп 24 унции. 13,7 14,7 0 0,5 74 0 0 0 5 0
Патока 18 унций. 13,6 9,0 0 10.3 244 0 1,9 7,5 146 0
Клубничное варенье 1 фунт. 20,5 6.4 11 0,4 7 0,2 0,2 0,4 3 0

Поскольку все питательные вещества нормализованы по цене, наша цель — просто свести к минимуму количество продуктов.

В 1944 году Стиглер вычислил лучший ответ, который только мог, и с грустью отметил:

...похоже, не существует какого-либо прямого метода нахождения минимума линейной функции при соблюдении линейных условий.

Он нашел диету, которая стоила 39,93 доллара в год в долларах 1939 года. В 1947 году Джек Ладерман применил симплексный метод (тогда это было недавнее изобретение!) для определения оптимального решения. Чтобы найти ответ, потребовалось 120 человеко-дней работы девяти клерков с настольными калькуляторами.

Решение с использованием линейного решателя

В следующих разделах представлена ​​программа, решающая проблему диеты Стиглера.

Импортируйте оболочку линейного решателя

Импортируйте оболочку линейного решателя OR-Tools, интерфейс для линейного решателя [GLOP](/optimization/mip/glop0, как показано ниже.

Питон

from ortools.linear_solver import pywraplp

С++

#include <array>
#include <memory>
#include <string>
#include <utility>  // std::pair
#include <vector>

#include "absl/flags/flag.h"
#include "absl/log/flags.h"
#include "ortools/base/init_google.h"
#include "ortools/base/logging.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;
import java.util.ArrayList;
import java.util.List;

С#

using System;
using System.Collections.Generic;
using Google.OrTools.LinearSolver;

Данные по проблеме

Следующий код создает массив nutrients для минимальных потребностей в питательных веществах и массив data для таблицы данных о питательных веществах в любом растворе.

Питон

# Nutrient minimums.
nutrients = [
    ["Calories (kcal)", 3],
    ["Protein (g)", 70],
    ["Calcium (g)", 0.8],
    ["Iron (mg)", 12],
    ["Vitamin A (KIU)", 5],
    ["Vitamin B1 (mg)", 1.8],
    ["Vitamin B2 (mg)", 2.7],
    ["Niacin (mg)", 18],
    ["Vitamin C (mg)", 75],
]

# Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g),
# Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg),
# Niacin (mg), Vitamin C (mg)
data = [
    # fmt: off
  ['Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0],
  ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0],
  ['Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0],
  ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0],
  ['Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0],
  ['Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0],
  ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0],
  ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0],
  ['White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0],
  ['Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0],
  ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0],
  ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0],
  ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0],
  ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177],
  ['Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60],
  ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0],
  ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0],
  ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0],
  ['Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0],
  ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17],
  ['Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0],
  ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0],
  ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0],
  ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0],
  ['Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0],
  ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0],
  ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0],
  ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0],
  ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0],
  ['Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525],
  ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0],
  ['Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0],
  ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0],
  ['Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0],
  ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0],
  ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0],
  ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0],
  ['Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46],
  ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0],
  ['Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0],
  ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544],
  ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498],
  ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952],
  ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998],
  ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862],
  ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369],
  ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608],
  ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313],
  ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449],
  ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184],
  ['Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522],
  ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755],
  ['Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912],
  ['Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196],
  ['Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81],
  ['Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399],
  ['Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272],
  ['Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431],
  ['Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0],
  ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218],
  ['Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370],
  ['Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253],
  ['Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862],
  ['Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57],
  ['Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257],
  ['Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136],
  ['Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0],
  ['Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0],
  ['Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0],
  ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0],
  ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0],
  ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0],
  ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0],
  ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0],
  ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0],
  ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0],
  ['Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0],
    # fmt: on
]

С++

// Nutrient minimums.
const std::vector<std::pair<std::string, double>> nutrients = {
    {"Calories (kcal)", 3.0}, {"Protein (g)", 70.0},
    {"Calcium (g)", 0.8},     {"Iron (mg)", 12.0},
    {"Vitamin A (kIU)", 5.0}, {"Vitamin B1 (mg)", 1.8},
    {"Vitamin B2 (mg)", 2.7}, {"Niacin (mg)", 18.0},
    {"Vitamin C (mg)", 75.0}};

struct Commodity {
  std::string name;  //!< Commodity name
  std::string unit;  //!< Unit
  double price;      //!< 1939 price per unit (cents)
  //! Calories (kcal),
  //! Protein (g),
  //! Calcium (g),
  //! Iron (mg),
  //! Vitamin A (kIU),
  //! Vitamin B1 (mg),
  //! Vitamin B2 (mg),
  //! Niacin (mg),
  //! Vitamin C (mg)
  std::array<double, 9> nutrients;
};

std::vector<Commodity> data = {
    {"Wheat Flour (Enriched)",
     "10 lb.",
     36,
     {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}},
    {"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}},
    {"Wheat Cereal (Enriched)",
     "28 oz.",
     24.2,
     {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}},
    {"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}},
    {"Corn Meal",
     "1 lb.",
     4.6,
     {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}},
    {"Hominy Grits",
     "24 oz.",
     8.5,
     {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}},
    {"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}},
    {"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}},
    {"White Bread (Enriched)",
     "1 lb.",
     7.9,
     {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}},
    {"Whole Wheat Bread",
     "1 lb.",
     9.1,
     {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}},
    {"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}},
    {"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}},
    {"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}},
    {"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}},
    {"Evaporated Milk (can)",
     "14.5 oz.",
     6.7,
     {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}},
    {"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}},
    {"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}},
    {"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}},
    {"Cheese (Cheddar)",
     "1 lb.",
     24.2,
     {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}},
    {"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}},
    {"Peanut Butter",
     "1 lb.",
     17.9,
     {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}},
    {"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}},
    {"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}},
    {"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}},
    {"Sirloin Steak",
     "1 lb.",
     39.6,
     {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}},
    {"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}},
    {"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}},
    {"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}},
    {"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}},
    {"Liver (Beef)",
     "1 lb.",
     26.8,
     {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}},
    {"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}},
    {"Lamb Chops (Rib)",
     "1 lb.",
     36.6,
     {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}},
    {"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}},
    {"Pork Loin Roast",
     "1 lb.",
     24.2,
     {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}},
    {"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}},
    {"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}},
    {"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}},
    {"Roasting Chicken",
     "1 lb.",
     30.3,
     {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}},
    {"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}},
    {"Salmon, Pink (can)",
     "16 oz.",
     13,
     {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}},
    {"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}},
    {"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}},
    {"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}},
    {"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}},
    {"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}},
    {"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}},
    {"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}},
    {"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}},
    {"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}},
    {"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}},
    {"Potatoes",
     "15 lb.",
     34,
     {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}},
    {"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}},
    {"Sweet Potatoes",
     "1 lb.",
     5.1,
     {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}},
    {"Peaches (can)",
     "No. 2 1/2",
     16.8,
     {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}},
    {"Pears (can)",
     "No. 2 1/2",
     20.4,
     {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}},
    {"Pineapple (can)",
     "No. 2 1/2",
     21.3,
     {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}},
    {"Asparagus (can)",
     "No. 2",
     27.7,
     {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}},
    {"Green Beans (can)",
     "No. 2",
     10,
     {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}},
    {"Pork and Beans (can)",
     "16 oz.",
     7.1,
     {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}},
    {"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}},
    {"Peas (can)",
     "No. 2",
     13.8,
     {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}},
    {"Tomatoes (can)",
     "No. 2",
     8.6,
     {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}},
    {"Tomato Soup (can)",
     "10 1/2 oz.",
     7.6,
     {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}},
    {"Peaches, Dried",
     "1 lb.",
     15.7,
     {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}},
    {"Prunes, Dried",
     "1 lb.",
     9,
     {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}},
    {"Raisins, Dried",
     "15 oz.",
     9.4,
     {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}},
    {"Peas, Dried",
     "1 lb.",
     7.9,
     {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}},
    {"Lima Beans, Dried",
     "1 lb.",
     8.9,
     {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}},
    {"Navy Beans, Dried",
     "1 lb.",
     5.9,
     {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}},
    {"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}},
    {"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}},
    {"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}},
    {"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}},
    {"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}},
    {"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}},
    {"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}},
    {"Strawberry Preserves",
     "1 lb.",
     20.5,
     {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};

Ява

// Nutrient minimums.
List<Object[]> nutrients = new ArrayList<>();
nutrients.add(new Object[] {"Calories (kcal)", 3.0});
nutrients.add(new Object[] {"Protein (g)", 70.0});
nutrients.add(new Object[] {"Calcium (g)", 0.8});
nutrients.add(new Object[] {"Iron (mg)", 12.0});
nutrients.add(new Object[] {"Vitamin A (kIU)", 5.0});
nutrients.add(new Object[] {"Vitamin B1 (mg)", 1.8});
nutrients.add(new Object[] {"Vitamin B2 (mg)", 2.7});
nutrients.add(new Object[] {"Niacin (mg)", 18.0});
nutrients.add(new Object[] {"Vitamin C (mg)", 75.0});

List<Object[]> data = new ArrayList<>();
data.add(new Object[] {"Wheat Flour (Enriched)", "10 lb.", 36,
    new double[] {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}});
data.add(new Object[] {
    "Macaroni", "1 lb.", 14.1, new double[] {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}});
data.add(new Object[] {"Wheat Cereal (Enriched)", "28 oz.", 24.2,
    new double[] {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}});
data.add(new Object[] {
    "Corn Flakes", "8 oz.", 7.1, new double[] {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}});
data.add(new Object[] {
    "Corn Meal", "1 lb.", 4.6, new double[] {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}});
data.add(new Object[] {
    "Hominy Grits", "24 oz.", 8.5, new double[] {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}});
data.add(
    new Object[] {"Rice", "1 lb.", 7.5, new double[] {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}});
data.add(new Object[] {
    "Rolled Oats", "1 lb.", 7.1, new double[] {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}});
data.add(new Object[] {"White Bread (Enriched)", "1 lb.", 7.9,
    new double[] {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}});
data.add(new Object[] {"Whole Wheat Bread", "1 lb.", 9.1,
    new double[] {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}});
data.add(new Object[] {
    "Rye Bread", "1 lb.", 9.1, new double[] {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}});
data.add(new Object[] {
    "Pound Cake", "1 lb.", 24.8, new double[] {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}});
data.add(new Object[] {
    "Soda Crackers", "1 lb.", 15.1, new double[] {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}});
data.add(
    new Object[] {"Milk", "1 qt.", 11, new double[] {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}});
data.add(new Object[] {"Evaporated Milk (can)", "14.5 oz.", 6.7,
    new double[] {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}});
data.add(
    new Object[] {"Butter", "1 lb.", 30.8, new double[] {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}});
data.add(new Object[] {
    "Oleomargarine", "1 lb.", 16.1, new double[] {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}});
data.add(new Object[] {
    "Eggs", "1 doz.", 32.6, new double[] {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}});
data.add(new Object[] {"Cheese (Cheddar)", "1 lb.", 24.2,
    new double[] {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}});
data.add(new Object[] {
    "Cream", "1/2 pt.", 14.1, new double[] {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}});
data.add(new Object[] {
    "Peanut Butter", "1 lb.", 17.9, new double[] {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}});
data.add(new Object[] {
    "Mayonnaise", "1/2 pt.", 16.7, new double[] {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}});
data.add(new Object[] {"Crisco", "1 lb.", 20.3, new double[] {20.1, 0, 0, 0, 0, 0, 0, 0, 0}});
data.add(new Object[] {"Lard", "1 lb.", 9.8, new double[] {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}});
data.add(new Object[] {
    "Sirloin Steak", "1 lb.", 39.6, new double[] {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}});
data.add(new Object[] {
    "Round Steak", "1 lb.", 36.4, new double[] {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}});
data.add(
    new Object[] {"Rib Roast", "1 lb.", 29.2, new double[] {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}});
data.add(new Object[] {
    "Chuck Roast", "1 lb.", 22.6, new double[] {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}});
data.add(
    new Object[] {"Plate", "1 lb.", 14.6, new double[] {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}});
data.add(new Object[] {"Liver (Beef)", "1 lb.", 26.8,
    new double[] {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}});
data.add(new Object[] {
    "Leg of Lamb", "1 lb.", 27.6, new double[] {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}});
data.add(new Object[] {
    "Lamb Chops (Rib)", "1 lb.", 36.6, new double[] {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}});
data.add(new Object[] {
    "Pork Chops", "1 lb.", 30.7, new double[] {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}});
data.add(new Object[] {
    "Pork Loin Roast", "1 lb.", 24.2, new double[] {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}});
data.add(new Object[] {
    "Bacon", "1 lb.", 25.6, new double[] {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}});
data.add(new Object[] {
    "Ham, smoked", "1 lb.", 27.4, new double[] {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}});
data.add(new Object[] {
    "Salt Pork", "1 lb.", 16, new double[] {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}});
data.add(new Object[] {"Roasting Chicken", "1 lb.", 30.3,
    new double[] {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}});
data.add(new Object[] {
    "Veal Cutlets", "1 lb.", 42.3, new double[] {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}});
data.add(new Object[] {
    "Salmon, Pink (can)", "16 oz.", 13, new double[] {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}});
data.add(new Object[] {
    "Apples", "1 lb.", 4.4, new double[] {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}});
data.add(new Object[] {
    "Bananas", "1 lb.", 6.1, new double[] {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}});
data.add(
    new Object[] {"Lemons", "1 doz.", 26, new double[] {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}});
data.add(new Object[] {
    "Oranges", "1 doz.", 30.9, new double[] {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}});
data.add(new Object[] {
    "Green Beans", "1 lb.", 7.1, new double[] {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}});
data.add(new Object[] {
    "Cabbage", "1 lb.", 3.7, new double[] {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}});
data.add(new Object[] {
    "Carrots", "1 bunch", 4.7, new double[] {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}});
data.add(new Object[] {
    "Celery", "1 stalk", 7.3, new double[] {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}});
data.add(new Object[] {
    "Lettuce", "1 head", 8.2, new double[] {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}});
data.add(new Object[] {
    "Onions", "1 lb.", 3.6, new double[] {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}});
data.add(new Object[] {
    "Potatoes", "15 lb.", 34, new double[] {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}});
data.add(new Object[] {
    "Spinach", "1 lb.", 8.1, new double[] {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}});
data.add(new Object[] {"Sweet Potatoes", "1 lb.", 5.1,
    new double[] {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}});
data.add(new Object[] {"Peaches (can)", "No. 2 1/2", 16.8,
    new double[] {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}});
data.add(new Object[] {
    "Pears (can)", "No. 2 1/2", 20.4, new double[] {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}});
data.add(new Object[] {
    "Pineapple (can)", "No. 2 1/2", 21.3, new double[] {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}});
data.add(new Object[] {"Asparagus (can)", "No. 2", 27.7,
    new double[] {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}});
data.add(new Object[] {
    "Green Beans (can)", "No. 2", 10, new double[] {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}});
data.add(new Object[] {"Pork and Beans (can)", "16 oz.", 7.1,
    new double[] {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}});
data.add(new Object[] {
    "Corn (can)", "No. 2", 10.4, new double[] {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}});
data.add(new Object[] {
    "Peas (can)", "No. 2", 13.8, new double[] {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}});
data.add(new Object[] {
    "Tomatoes (can)", "No. 2", 8.6, new double[] {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}});
data.add(new Object[] {"Tomato Soup (can)", "10 1/2 oz.", 7.6,
    new double[] {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}});
data.add(new Object[] {
    "Peaches, Dried", "1 lb.", 15.7, new double[] {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}});
data.add(new Object[] {
    "Prunes, Dried", "1 lb.", 9, new double[] {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}});
data.add(new Object[] {"Raisins, Dried", "15 oz.", 9.4,
    new double[] {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}});
data.add(new Object[] {
    "Peas, Dried", "1 lb.", 7.9, new double[] {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}});
data.add(new Object[] {"Lima Beans, Dried", "1 lb.", 8.9,
    new double[] {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}});
data.add(new Object[] {"Navy Beans, Dried", "1 lb.", 5.9,
    new double[] {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}});
data.add(new Object[] {"Coffee", "1 lb.", 22.4, new double[] {0, 0, 0, 0, 0, 4, 5.1, 50, 0}});
data.add(new Object[] {"Tea", "1/4 lb.", 17.4, new double[] {0, 0, 0, 0, 0, 0, 2.3, 42, 0}});
data.add(
    new Object[] {"Cocoa", "8 oz.", 8.6, new double[] {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}});
data.add(new Object[] {
    "Chocolate", "8 oz.", 16.2, new double[] {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}});
data.add(new Object[] {"Sugar", "10 lb.", 51.7, new double[] {34.9, 0, 0, 0, 0, 0, 0, 0, 0}});
data.add(new Object[] {
    "Corn Syrup", "24 oz.", 13.7, new double[] {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}});
data.add(new Object[] {
    "Molasses", "18 oz.", 13.6, new double[] {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}});
data.add(new Object[] {"Strawberry Preserves", "1 lb.", 20.5,
    new double[] {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}});

С#

// Nutrient minimums.
(String Name, double Value)[] nutrients =
    new[] { ("Calories (kcal)", 3.0), ("Protein (g)", 70.0),    ("Calcium (g)", 0.8),
            ("Iron (mg)", 12.0),      ("Vitamin A (kIU)", 5.0), ("Vitamin B1 (mg)", 1.8),
            ("Vitamin B2 (mg)", 2.7), ("Niacin (mg)", 18.0),    ("Vitamin C (mg)", 75.0) };

(String Name, String Unit, double Price, double[] Nutrients)[] data = new[] {
    ("Wheat Flour (Enriched)", "10 lb.", 36, new double[] { 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 }),
    ("Macaroni", "1 lb.", 14.1, new double[] { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 }),
    ("Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] { 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 }),
    ("Corn Flakes", "8 oz.", 7.1, new double[] { 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 }),
    ("Corn Meal", "1 lb.", 4.6, new double[] { 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 }),
    ("Hominy Grits", "24 oz.", 8.5, new double[] { 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 }),
    ("Rice", "1 lb.", 7.5, new double[] { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 }),
    ("Rolled Oats", "1 lb.", 7.1, new double[] { 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 }),
    ("White Bread (Enriched)", "1 lb.", 7.9, new double[] { 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 }),
    ("Whole Wheat Bread", "1 lb.", 9.1, new double[] { 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 }),
    ("Rye Bread", "1 lb.", 9.1, new double[] { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 }),
    ("Pound Cake", "1 lb.", 24.8, new double[] { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 }),
    ("Soda Crackers", "1 lb.", 15.1, new double[] { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 }),
    ("Milk", "1 qt.", 11, new double[] { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 }),
    ("Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] { 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 }),
    ("Butter", "1 lb.", 30.8, new double[] { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 }),
    ("Oleomargarine", "1 lb.", 16.1, new double[] { 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 }),
    ("Eggs", "1 doz.", 32.6, new double[] { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 }),
    ("Cheese (Cheddar)", "1 lb.", 24.2, new double[] { 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 }),
    ("Cream", "1/2 pt.", 14.1, new double[] { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 }),
    ("Peanut Butter", "1 lb.", 17.9, new double[] { 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 }),
    ("Mayonnaise", "1/2 pt.", 16.7, new double[] { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 }),
    ("Crisco", "1 lb.", 20.3, new double[] { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 }),
    ("Lard", "1 lb.", 9.8, new double[] { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 }),
    ("Sirloin Steak", "1 lb.", 39.6, new double[] { 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 }),
    ("Round Steak", "1 lb.", 36.4, new double[] { 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 }),
    ("Rib Roast", "1 lb.", 29.2, new double[] { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 }),
    ("Chuck Roast", "1 lb.", 22.6, new double[] { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 }),
    ("Plate", "1 lb.", 14.6, new double[] { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 }),
    ("Liver (Beef)", "1 lb.", 26.8, new double[] { 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 }),
    ("Leg of Lamb", "1 lb.", 27.6, new double[] { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 }),
    ("Lamb Chops (Rib)", "1 lb.", 36.6, new double[] { 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 }),
    ("Pork Chops", "1 lb.", 30.7, new double[] { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 }),
    ("Pork Loin Roast", "1 lb.", 24.2, new double[] { 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 }),
    ("Bacon", "1 lb.", 25.6, new double[] { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 }),
    ("Ham, smoked", "1 lb.", 27.4, new double[] { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 }),
    ("Salt Pork", "1 lb.", 16, new double[] { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 }),
    ("Roasting Chicken", "1 lb.", 30.3, new double[] { 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 }),
    ("Veal Cutlets", "1 lb.", 42.3, new double[] { 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 }),
    ("Salmon, Pink (can)", "16 oz.", 13, new double[] { 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 }),
    ("Apples", "1 lb.", 4.4, new double[] { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 }),
    ("Bananas", "1 lb.", 6.1, new double[] { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 }),
    ("Lemons", "1 doz.", 26, new double[] { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 }),
    ("Oranges", "1 doz.", 30.9, new double[] { 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 }),
    ("Green Beans", "1 lb.", 7.1, new double[] { 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 }),
    ("Cabbage", "1 lb.", 3.7, new double[] { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 }),
    ("Carrots", "1 bunch", 4.7, new double[] { 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 }),
    ("Celery", "1 stalk", 7.3, new double[] { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 }),
    ("Lettuce", "1 head", 8.2, new double[] { 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 }),
    ("Onions", "1 lb.", 3.6, new double[] { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 }),
    ("Potatoes", "15 lb.", 34, new double[] { 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 }),
    ("Spinach", "1 lb.", 8.1, new double[] { 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 }),
    ("Sweet Potatoes", "1 lb.", 5.1, new double[] { 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 }),
    ("Peaches (can)", "No. 2 1/2", 16.8, new double[] { 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 }),
    ("Pears (can)", "No. 2 1/2", 20.4, new double[] { 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 }),
    ("Pineapple (can)", "No. 2 1/2", 21.3, new double[] { 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 }),
    ("Asparagus (can)", "No. 2", 27.7, new double[] { 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 }),
    ("Green Beans (can)", "No. 2", 10, new double[] { 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 }),
    ("Pork and Beans (can)", "16 oz.", 7.1, new double[] { 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 }),
    ("Corn (can)", "No. 2", 10.4, new double[] { 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 }),
    ("Peas (can)", "No. 2", 13.8, new double[] { 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 }),
    ("Tomatoes (can)", "No. 2", 8.6, new double[] { 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 }),
    ("Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] { 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 }),
    ("Peaches, Dried", "1 lb.", 15.7, new double[] { 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 }),
    ("Prunes, Dried", "1 lb.", 9, new double[] { 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 }),
    ("Raisins, Dried", "15 oz.", 9.4, new double[] { 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 }),
    ("Peas, Dried", "1 lb.", 7.9, new double[] { 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 }),
    ("Lima Beans, Dried", "1 lb.", 8.9, new double[] { 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 }),
    ("Navy Beans, Dried", "1 lb.", 5.9, new double[] { 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 }),
    ("Coffee", "1 lb.", 22.4, new double[] { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 }),
    ("Tea", "1/4 lb.", 17.4, new double[] { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 }),
    ("Cocoa", "8 oz.", 8.6, new double[] { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 }),
    ("Chocolate", "8 oz.", 16.2, new double[] { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 }),
    ("Sugar", "10 lb.", 51.7, new double[] { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 }),
    ("Corn Syrup", "24 oz.", 13.7, new double[] { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 }),
    ("Molasses", "18 oz.", 13.6, new double[] { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 }),
    ("Strawberry Preserves", "1 lb.", 20.5, new double[] { 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 })
};

Объявить решатель LP

Следующий код создает экземпляр оболочки MPsolver .

Питон

# Instantiate a Glop solver and naming it.
solver = pywraplp.Solver.CreateSolver("GLOP")
if not solver:
    return

С++

// Create the linear solver with the GLOP backend.
std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));

Ява

// Create the linear solver with the GLOP backend.
MPSolver solver = MPSolver.createSolver("GLOP");
if (solver == null) {
  System.out.println("Could not create solver GLOP");
  return;
}

С#

// Create the linear solver with the GLOP backend.
Solver solver = Solver.CreateSolver("GLOP");
if (solver is null)
{
    return;
}

Создайте переменные

Следующий код создает переменные для проблемы.

Питон

# Declare an array to hold our variables.
foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]

print("Number of variables =", solver.NumVariables())

С++

std::vector<MPVariable*> foods;
const double infinity = solver->infinity();
for (const Commodity& commodity : data) {
  foods.push_back(solver->MakeNumVar(0.0, infinity, commodity.name));
}
LOG(INFO) << "Number of variables = " << solver->NumVariables();

Ява

double infinity = java.lang.Double.POSITIVE_INFINITY;
List<MPVariable> foods = new ArrayList<>();
for (int i = 0; i < data.size(); ++i) {
  foods.add(solver.makeNumVar(0.0, infinity, (String) data.get(i)[0]));
}
System.out.println("Number of variables = " + solver.numVariables());

С#

List<Variable> foods = new List<Variable>();
for (int i = 0; i < data.Length; ++i)
{
    foods.Add(solver.MakeNumVar(0.0, double.PositiveInfinity, data[i].Name));
}
Console.WriteLine($"Number of variables = {solver.NumVariables()}");

Метод MakeNumVar создает одну переменную food[i] для каждой строки таблицы. Как упоминалось ранее, данные о питании указаны на доллар, поэтому food[i] — это сумма денег, которую можно потратить на товар i .

Определите ограничения

Ограничения диеты Стиглера требуют, чтобы общее количество питательных веществ, содержащихся во всех продуктах, соответствовало, по крайней мере, минимальной потребности для каждого питательного вещества. Далее мы запишем эти ограничения в виде неравенств, включающих массивы data и nutrients , а также переменные food[i] .

Во-первых, количество питательных веществ i , обеспечиваемых пищей j на доллар, равно data[j][i+3] (мы добавляем 3 к индексу столбца, поскольку данные о питательных веществах начинаются в четвертом столбце data ). будет потрачено на еду jfood[j] , количество питательных веществ i обеспечиваемых пищей j , равно\(data[j][i+3] \cdot food[j]\). Наконец, поскольку минимальное требование к питательному веществу i — это nutrients[i][1] , мы можем записать ограничение i следующим образом:

\( \sum_{j} data[j][i+3] \cdot food[j] \geq nutrients[i][1] \;\;\;\;\; (1) \)
Следующий код определяет эти ограничения.

Питон

# Create the constraints, one per nutrient.
constraints = []
for i, nutrient in enumerate(nutrients):
    constraints.append(solver.Constraint(nutrient[1], solver.infinity()))
    for j, item in enumerate(data):
        constraints[i].SetCoefficient(foods[j], item[i + 3])

print("Number of constraints =", solver.NumConstraints())

С++

// Create the constraints, one per nutrient.
std::vector<MPConstraint*> constraints;
for (std::size_t i = 0; i < nutrients.size(); ++i) {
  constraints.push_back(
      solver->MakeRowConstraint(nutrients[i].second, infinity));
  for (std::size_t j = 0; j < data.size(); ++j) {
    constraints.back()->SetCoefficient(foods[j], data[j].nutrients[i]);
  }
}
LOG(INFO) << "Number of constraints = " << solver->NumConstraints();

Ява

MPConstraint[] constraints = new MPConstraint[nutrients.size()];
for (int i = 0; i < nutrients.size(); ++i) {
  constraints[i] = solver.makeConstraint(
      (double) nutrients.get(i)[1], infinity, (String) nutrients.get(i)[0]);
  for (int j = 0; j < data.size(); ++j) {
    constraints[i].setCoefficient(foods.get(j), ((double[]) data.get(j)[3])[i]);
  }
  // constraints.add(constraint);
}
System.out.println("Number of constraints = " + solver.numConstraints());

С#

List<Constraint> constraints = new List<Constraint>();
for (int i = 0; i < nutrients.Length; ++i)
{
    Constraint constraint =
        solver.MakeConstraint(nutrients[i].Value, double.PositiveInfinity, nutrients[i].Name);
    for (int j = 0; j < data.Length; ++j)
    {
        constraint.SetCoefficient(foods[j], data[j].Nutrients[i]);
    }
    constraints.Add(constraint);
}
Console.WriteLine($"Number of constraints = {solver.NumConstraints()}");

Метод Constraint Python (соответствующий методу C++ MakeRowConstraint ) создает ограничения для проблемы. Для каждого i constraint(nutrients[i][1], solver.infinity)

Это создает ограничение, при котором линейная комбинация переменных food[j] (определенных далее) больше или равна nutrients[i][1] . Коэффициенты линейного выражения определяются методом SetCoefficient следующим образом: SetCoefficient(food[j], data[j][i+3]

Это устанавливает коэффициент food[j] как data[j][i+3] .

Объединив все это, код определяет ограничения, выраженные в (1) выше.

Создайте цель

Следующий код определяет целевую функцию для задачи.

Питон

# Objective function: Minimize the sum of (price-normalized) foods.
objective = solver.Objective()
for food in foods:
    objective.SetCoefficient(food, 1)
objective.SetMinimization()

С++

MPObjective* const objective = solver->MutableObjective();
for (size_t i = 0; i < data.size(); ++i) {
  objective->SetCoefficient(foods[i], 1);
}
objective->SetMinimization();

Ява

MPObjective objective = solver.objective();
for (int i = 0; i < data.size(); ++i) {
  objective.setCoefficient(foods.get(i), 1);
}
objective.setMinimization();

С#

Objective objective = solver.Objective();
for (int i = 0; i < data.Length; ++i)
{
    objective.SetCoefficient(foods[i], 1);
}
objective.SetMinimization();

Целевая функция — это общая стоимость еды, которая представляет собой сумму переменных food[i] .

Метод SetCoefficient устанавливает коэффициенты целевой функции, которые в данном случае равны 1 . Наконец, SetMinimization объявляет это проблемой минимизации.

Вызов решателя

Следующий код вызывает решатель.

Питон

print(f"Solving with {solver.SolverVersion()}")
status = solver.Solve()

С++

const MPSolver::ResultStatus result_status = solver->Solve();

Ява

final MPSolver.ResultStatus resultStatus = solver.solve();

С#

Solver.ResultStatus resultStatus = solver.Solve();

Glop решает проблему на обычном компьютере менее чем за 300 миллисекунд:

Показать решение

Следующий код отображает решение.

Питон

# Check that the problem has an optimal solution.
if status != solver.OPTIMAL:
    print("The problem does not have an optimal solution!")
    if status == solver.FEASIBLE:
        print("A potentially suboptimal solution was found.")
    else:
        print("The solver could not solve the problem.")
        exit(1)

# Display the amounts (in dollars) to purchase of each food.
nutrients_result = [0] * len(nutrients)
print("\nAnnual Foods:")
for i, food in enumerate(foods):
    if food.solution_value() > 0.0:
        print("{}: ${}".format(data[i][0], 365.0 * food.solution_value()))
        for j, _ in enumerate(nutrients):
            nutrients_result[j] += data[i][j + 3] * food.solution_value()
print("\nOptimal annual price: ${:.4f}".format(365.0 * objective.Value()))

print("\nNutrients per day:")
for i, nutrient in enumerate(nutrients):
    print(
        "{}: {:.2f} (min {})".format(nutrient[0], nutrients_result[i], nutrient[1])
    )

С++

// Check that the problem has an optimal solution.
if (result_status != MPSolver::OPTIMAL) {
  LOG(INFO) << "The problem does not have an optimal solution!";
  if (result_status == MPSolver::FEASIBLE) {
    LOG(INFO) << "A potentially suboptimal solution was found";
  } else {
    LOG(INFO) << "The solver could not solve the problem.";
    return;
  }
}

std::vector<double> nutrients_result(nutrients.size());
LOG(INFO) << "";
LOG(INFO) << "Annual Foods:";
for (std::size_t i = 0; i < data.size(); ++i) {
  if (foods[i]->solution_value() > 0.0) {
    LOG(INFO) << data[i].name << ": $"
              << std::to_string(365. * foods[i]->solution_value());
    for (std::size_t j = 0; j < nutrients.size(); ++j) {
      nutrients_result[j] +=
          data[i].nutrients[j] * foods[i]->solution_value();
    }
  }
}
LOG(INFO) << "";
LOG(INFO) << "Optimal annual price: $"
          << std::to_string(365. * objective->Value());
LOG(INFO) << "";
LOG(INFO) << "Nutrients per day:";
for (std::size_t i = 0; i < nutrients.size(); ++i) {
  LOG(INFO) << nutrients[i].first << ": "
            << std::to_string(nutrients_result[i]) << " (min "
            << std::to_string(nutrients[i].second) << ")";
}

Ява

// Check that the problem has an optimal solution.
if (resultStatus != MPSolver.ResultStatus.OPTIMAL) {
  System.err.println("The problem does not have an optimal solution!");
  if (resultStatus == MPSolver.ResultStatus.FEASIBLE) {
    System.err.println("A potentially suboptimal solution was found.");
  } else {
    System.err.println("The solver could not solve the problem.");
    return;
  }
}

// Display the amounts (in dollars) to purchase of each food.
double[] nutrientsResult = new double[nutrients.size()];
System.out.println("\nAnnual Foods:");
for (int i = 0; i < foods.size(); ++i) {
  if (foods.get(i).solutionValue() > 0.0) {
    System.out.println((String) data.get(i)[0] + ": $" + 365 * foods.get(i).solutionValue());
    for (int j = 0; j < nutrients.size(); ++j) {
      nutrientsResult[j] += ((double[]) data.get(i)[3])[j] * foods.get(i).solutionValue();
    }
  }
}
System.out.println("\nOptimal annual price: $" + 365 * objective.value());

System.out.println("\nNutrients per day:");
for (int i = 0; i < nutrients.size(); ++i) {
  System.out.println(
      nutrients.get(i)[0] + ": " + nutrientsResult[i] + " (min " + nutrients.get(i)[1] + ")");
}

С#

// Check that the problem has an optimal solution.
if (resultStatus != Solver.ResultStatus.OPTIMAL)
{
    Console.WriteLine("The problem does not have an optimal solution!");
    if (resultStatus == Solver.ResultStatus.FEASIBLE)
    {
        Console.WriteLine("A potentially suboptimal solution was found.");
    }
    else
    {
        Console.WriteLine("The solver could not solve the problem.");
        return;
    }
}

// Display the amounts (in dollars) to purchase of each food.
double[] nutrientsResult = new double[nutrients.Length];
Console.WriteLine("\nAnnual Foods:");
for (int i = 0; i < foods.Count; ++i)
{
    if (foods[i].SolutionValue() > 0.0)
    {
        Console.WriteLine($"{data[i].Name}: ${365 * foods[i].SolutionValue():N2}");
        for (int j = 0; j < nutrients.Length; ++j)
        {
            nutrientsResult[j] += data[i].Nutrients[j] * foods[i].SolutionValue();
        }
    }
}
Console.WriteLine($"\nOptimal annual price: ${365 * objective.Value():N2}");

Console.WriteLine("\nNutrients per day:");
for (int i = 0; i < nutrients.Length; ++i)
{
    Console.WriteLine($"{nutrients[i].Name}: {nutrientsResult[i]:N2} (min {nutrients[i].Value})");
}

Вот результат работы программы.

make rpy_stigler_diet
"/usr/bin/python3.11" ortools/linear_solver/samples/stigler_diet.py
Number of variables = 77
Number of constraints = 9

Annual Foods:
Wheat Flour (Enriched): $10.774457511918223
Liver (Beef): $0.6907834111074193
Cabbage: $4.093268864842877
Spinach: $1.8277960703546996
Navy Beans, Dried: $22.275425687243036

Optimal annual price: $39.6617

Nutrients per day:
Calories (kcal): 3.00 (min 3)
Protein (g): 147.41 (min 70)
Calcium (g): 0.80 (min 0.8)
Iron (mg): 60.47 (min 12)
Vitamin A (KIU): 5.00 (min 5)
Vitamin B1 (mg): 4.12 (min 1.8)
Vitamin B2 (mg): 2.70 (min 2.7)
Niacin (mg): 27.32 (min 18)
Vitamin C (mg): 75.00 (min 75)

Advanced usage:
Problem solved in  1  milliseconds
Problem solved in  14  iterations

Полный код программы

Полный код программы диеты Стиглера показан ниже.

Питон

"""The Stigler diet problem.

A description of the problem can be found here:
https://en.wikipedia.org/wiki/Stigler_diet.
"""
from ortools.linear_solver import pywraplp


def main():
    """Entry point of the program."""
    # Instantiate the data problem.
    # Nutrient minimums.
    nutrients = [
        ["Calories (kcal)", 3],
        ["Protein (g)", 70],
        ["Calcium (g)", 0.8],
        ["Iron (mg)", 12],
        ["Vitamin A (KIU)", 5],
        ["Vitamin B1 (mg)", 1.8],
        ["Vitamin B2 (mg)", 2.7],
        ["Niacin (mg)", 18],
        ["Vitamin C (mg)", 75],
    ]

    # Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g),
    # Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg),
    # Niacin (mg), Vitamin C (mg)
    data = [
        # fmt: off
      ['Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0],
      ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0],
      ['Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0],
      ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0],
      ['Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0],
      ['Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0],
      ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0],
      ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0],
      ['White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0],
      ['Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0],
      ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0],
      ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0],
      ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0],
      ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177],
      ['Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60],
      ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0],
      ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0],
      ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0],
      ['Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0],
      ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17],
      ['Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0],
      ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0],
      ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0],
      ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0],
      ['Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0],
      ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0],
      ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0],
      ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0],
      ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0],
      ['Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525],
      ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0],
      ['Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0],
      ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0],
      ['Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0],
      ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0],
      ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0],
      ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0],
      ['Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46],
      ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0],
      ['Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0],
      ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544],
      ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498],
      ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952],
      ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998],
      ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862],
      ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369],
      ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608],
      ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313],
      ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449],
      ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184],
      ['Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522],
      ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755],
      ['Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912],
      ['Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196],
      ['Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81],
      ['Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399],
      ['Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272],
      ['Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431],
      ['Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0],
      ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218],
      ['Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370],
      ['Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253],
      ['Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862],
      ['Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57],
      ['Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257],
      ['Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136],
      ['Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0],
      ['Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0],
      ['Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0],
      ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0],
      ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0],
      ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0],
      ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0],
      ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0],
      ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0],
      ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0],
      ['Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0],
        # fmt: on
    ]

    # Instantiate a Glop solver and naming it.
    solver = pywraplp.Solver.CreateSolver("GLOP")
    if not solver:
        return

    # Declare an array to hold our variables.
    foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]

    print("Number of variables =", solver.NumVariables())

    # Create the constraints, one per nutrient.
    constraints = []
    for i, nutrient in enumerate(nutrients):
        constraints.append(solver.Constraint(nutrient[1], solver.infinity()))
        for j, item in enumerate(data):
            constraints[i].SetCoefficient(foods[j], item[i + 3])

    print("Number of constraints =", solver.NumConstraints())

    # Objective function: Minimize the sum of (price-normalized) foods.
    objective = solver.Objective()
    for food in foods:
        objective.SetCoefficient(food, 1)
    objective.SetMinimization()

    print(f"Solving with {solver.SolverVersion()}")
    status = solver.Solve()

    # Check that the problem has an optimal solution.
    if status != solver.OPTIMAL:
        print("The problem does not have an optimal solution!")
        if status == solver.FEASIBLE:
            print("A potentially suboptimal solution was found.")
        else:
            print("The solver could not solve the problem.")
            exit(1)

    # Display the amounts (in dollars) to purchase of each food.
    nutrients_result = [0] * len(nutrients)
    print("\nAnnual Foods:")
    for i, food in enumerate(foods):
        if food.solution_value() > 0.0:
            print("{}: ${}".format(data[i][0], 365.0 * food.solution_value()))
            for j, _ in enumerate(nutrients):
                nutrients_result[j] += data[i][j + 3] * food.solution_value()
    print("\nOptimal annual price: ${:.4f}".format(365.0 * objective.Value()))

    print("\nNutrients per day:")
    for i, nutrient in enumerate(nutrients):
        print(
            "{}: {:.2f} (min {})".format(nutrient[0], nutrients_result[i], nutrient[1])
        )

    print("\nAdvanced usage:")
    print(f"Problem solved in {solver.wall_time():d} milliseconds")
    print(f"Problem solved in {solver.iterations():d} iterations")


if __name__ == "__main__":
    main()

С++

// The Stigler diet problem.
#include <array>
#include <memory>
#include <string>
#include <utility>  // std::pair
#include <vector>

#include "absl/flags/flag.h"
#include "absl/log/flags.h"
#include "ortools/base/init_google.h"
#include "ortools/base/logging.h"
#include "ortools/linear_solver/linear_solver.h"

namespace operations_research {
void StiglerDiet() {
  // Nutrient minimums.
  const std::vector<std::pair<std::string, double>> nutrients = {
      {"Calories (kcal)", 3.0}, {"Protein (g)", 70.0},
      {"Calcium (g)", 0.8},     {"Iron (mg)", 12.0},
      {"Vitamin A (kIU)", 5.0}, {"Vitamin B1 (mg)", 1.8},
      {"Vitamin B2 (mg)", 2.7}, {"Niacin (mg)", 18.0},
      {"Vitamin C (mg)", 75.0}};

  struct Commodity {
    std::string name;  //!< Commodity name
    std::string unit;  //!< Unit
    double price;      //!< 1939 price per unit (cents)
    //! Calories (kcal),
    //! Protein (g),
    //! Calcium (g),
    //! Iron (mg),
    //! Vitamin A (kIU),
    //! Vitamin B1 (mg),
    //! Vitamin B2 (mg),
    //! Niacin (mg),
    //! Vitamin C (mg)
    std::array<double, 9> nutrients;
  };

  std::vector<Commodity> data = {
      {"Wheat Flour (Enriched)",
       "10 lb.",
       36,
       {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}},
      {"Macaroni", "1 lb.", 14.1, {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}},
      {"Wheat Cereal (Enriched)",
       "28 oz.",
       24.2,
       {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}},
      {"Corn Flakes", "8 oz.", 7.1, {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}},
      {"Corn Meal",
       "1 lb.",
       4.6,
       {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}},
      {"Hominy Grits",
       "24 oz.",
       8.5,
       {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}},
      {"Rice", "1 lb.", 7.5, {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}},
      {"Rolled Oats", "1 lb.", 7.1, {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}},
      {"White Bread (Enriched)",
       "1 lb.",
       7.9,
       {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}},
      {"Whole Wheat Bread",
       "1 lb.",
       9.1,
       {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}},
      {"Rye Bread", "1 lb.", 9.1, {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}},
      {"Pound Cake", "1 lb.", 24.8, {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}},
      {"Soda Crackers", "1 lb.", 15.1, {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}},
      {"Milk", "1 qt.", 11, {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}},
      {"Evaporated Milk (can)",
       "14.5 oz.",
       6.7,
       {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}},
      {"Butter", "1 lb.", 30.8, {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}},
      {"Oleomargarine", "1 lb.", 16.1, {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}},
      {"Eggs", "1 doz.", 32.6, {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}},
      {"Cheese (Cheddar)",
       "1 lb.",
       24.2,
       {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}},
      {"Cream", "1/2 pt.", 14.1, {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}},
      {"Peanut Butter",
       "1 lb.",
       17.9,
       {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}},
      {"Mayonnaise", "1/2 pt.", 16.7, {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}},
      {"Crisco", "1 lb.", 20.3, {20.1, 0, 0, 0, 0, 0, 0, 0, 0}},
      {"Lard", "1 lb.", 9.8, {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}},
      {"Sirloin Steak",
       "1 lb.",
       39.6,
       {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}},
      {"Round Steak", "1 lb.", 36.4, {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}},
      {"Rib Roast", "1 lb.", 29.2, {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}},
      {"Chuck Roast", "1 lb.", 22.6, {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}},
      {"Plate", "1 lb.", 14.6, {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}},
      {"Liver (Beef)",
       "1 lb.",
       26.8,
       {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}},
      {"Leg of Lamb", "1 lb.", 27.6, {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}},
      {"Lamb Chops (Rib)",
       "1 lb.",
       36.6,
       {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}},
      {"Pork Chops", "1 lb.", 30.7, {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}},
      {"Pork Loin Roast",
       "1 lb.",
       24.2,
       {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}},
      {"Bacon", "1 lb.", 25.6, {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}},
      {"Ham, smoked", "1 lb.", 27.4, {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}},
      {"Salt Pork", "1 lb.", 16, {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}},
      {"Roasting Chicken",
       "1 lb.",
       30.3,
       {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}},
      {"Veal Cutlets", "1 lb.", 42.3, {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}},
      {"Salmon, Pink (can)",
       "16 oz.",
       13,
       {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}},
      {"Apples", "1 lb.", 4.4, {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}},
      {"Bananas", "1 lb.", 6.1, {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}},
      {"Lemons", "1 doz.", 26, {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}},
      {"Oranges", "1 doz.", 30.9, {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}},
      {"Green Beans", "1 lb.", 7.1, {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}},
      {"Cabbage", "1 lb.", 3.7, {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}},
      {"Carrots", "1 bunch", 4.7, {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}},
      {"Celery", "1 stalk", 7.3, {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}},
      {"Lettuce", "1 head", 8.2, {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}},
      {"Onions", "1 lb.", 3.6, {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}},
      {"Potatoes",
       "15 lb.",
       34,
       {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}},
      {"Spinach", "1 lb.", 8.1, {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}},
      {"Sweet Potatoes",
       "1 lb.",
       5.1,
       {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}},
      {"Peaches (can)",
       "No. 2 1/2",
       16.8,
       {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}},
      {"Pears (can)",
       "No. 2 1/2",
       20.4,
       {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}},
      {"Pineapple (can)",
       "No. 2 1/2",
       21.3,
       {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}},
      {"Asparagus (can)",
       "No. 2",
       27.7,
       {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}},
      {"Green Beans (can)",
       "No. 2",
       10,
       {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}},
      {"Pork and Beans (can)",
       "16 oz.",
       7.1,
       {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}},
      {"Corn (can)", "No. 2", 10.4, {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}},
      {"Peas (can)",
       "No. 2",
       13.8,
       {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}},
      {"Tomatoes (can)",
       "No. 2",
       8.6,
       {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}},
      {"Tomato Soup (can)",
       "10 1/2 oz.",
       7.6,
       {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}},
      {"Peaches, Dried",
       "1 lb.",
       15.7,
       {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}},
      {"Prunes, Dried",
       "1 lb.",
       9,
       {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}},
      {"Raisins, Dried",
       "15 oz.",
       9.4,
       {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}},
      {"Peas, Dried",
       "1 lb.",
       7.9,
       {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}},
      {"Lima Beans, Dried",
       "1 lb.",
       8.9,
       {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}},
      {"Navy Beans, Dried",
       "1 lb.",
       5.9,
       {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}},
      {"Coffee", "1 lb.", 22.4, {0, 0, 0, 0, 0, 4, 5.1, 50, 0}},
      {"Tea", "1/4 lb.", 17.4, {0, 0, 0, 0, 0, 0, 2.3, 42, 0}},
      {"Cocoa", "8 oz.", 8.6, {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}},
      {"Chocolate", "8 oz.", 16.2, {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}},
      {"Sugar", "10 lb.", 51.7, {34.9, 0, 0, 0, 0, 0, 0, 0, 0}},
      {"Corn Syrup", "24 oz.", 13.7, {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}},
      {"Molasses", "18 oz.", 13.6, {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}},
      {"Strawberry Preserves",
       "1 lb.",
       20.5,
       {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}}};

  // Create the linear solver with the GLOP backend.
  std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));

  std::vector<MPVariable*> foods;
  const double infinity = solver->infinity();
  for (const Commodity& commodity : data) {
    foods.push_back(solver->MakeNumVar(0.0, infinity, commodity.name));
  }
  LOG(INFO) << "Number of variables = " << solver->NumVariables();

  // Create the constraints, one per nutrient.
  std::vector<MPConstraint*> constraints;
  for (std::size_t i = 0; i < nutrients.size(); ++i) {
    constraints.push_back(
        solver->MakeRowConstraint(nutrients[i].second, infinity));
    for (std::size_t j = 0; j < data.size(); ++j) {
      constraints.back()->SetCoefficient(foods[j], data[j].nutrients[i]);
    }
  }
  LOG(INFO) << "Number of constraints = " << solver->NumConstraints();

  MPObjective* const objective = solver->MutableObjective();
  for (size_t i = 0; i < data.size(); ++i) {
    objective->SetCoefficient(foods[i], 1);
  }
  objective->SetMinimization();

  const MPSolver::ResultStatus result_status = solver->Solve();

  // Check that the problem has an optimal solution.
  if (result_status != MPSolver::OPTIMAL) {
    LOG(INFO) << "The problem does not have an optimal solution!";
    if (result_status == MPSolver::FEASIBLE) {
      LOG(INFO) << "A potentially suboptimal solution was found";
    } else {
      LOG(INFO) << "The solver could not solve the problem.";
      return;
    }
  }

  std::vector<double> nutrients_result(nutrients.size());
  LOG(INFO) << "";
  LOG(INFO) << "Annual Foods:";
  for (std::size_t i = 0; i < data.size(); ++i) {
    if (foods[i]->solution_value() > 0.0) {
      LOG(INFO) << data[i].name << ": $"
                << std::to_string(365. * foods[i]->solution_value());
      for (std::size_t j = 0; j < nutrients.size(); ++j) {
        nutrients_result[j] +=
            data[i].nutrients[j] * foods[i]->solution_value();
      }
    }
  }
  LOG(INFO) << "";
  LOG(INFO) << "Optimal annual price: $"
            << std::to_string(365. * objective->Value());
  LOG(INFO) << "";
  LOG(INFO) << "Nutrients per day:";
  for (std::size_t i = 0; i < nutrients.size(); ++i) {
    LOG(INFO) << nutrients[i].first << ": "
              << std::to_string(nutrients_result[i]) << " (min "
              << std::to_string(nutrients[i].second) << ")";
  }

  LOG(INFO) << "";
  LOG(INFO) << "Advanced usage:";
  LOG(INFO) << "Problem solved in " << solver->wall_time() << " milliseconds";
  LOG(INFO) << "Problem solved in " << solver->iterations() << " iterations";
}
}  // namespace operations_research

int main(int argc, char** argv) {
  InitGoogle(argv[0], &argc, &argv, true);
  absl::SetFlag(&FLAGS_stderrthreshold, 0);
  operations_research::StiglerDiet();
  return EXIT_SUCCESS;
}

Ява

// The Stigler diet problem.
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;
import java.util.ArrayList;
import java.util.List;

/** Stigler diet example. */
public final class StiglerDiet {
  public static void main(String[] args) {
    Loader.loadNativeLibraries();
    // Nutrient minimums.
    List<Object[]> nutrients = new ArrayList<>();
    nutrients.add(new Object[] {"Calories (kcal)", 3.0});
    nutrients.add(new Object[] {"Protein (g)", 70.0});
    nutrients.add(new Object[] {"Calcium (g)", 0.8});
    nutrients.add(new Object[] {"Iron (mg)", 12.0});
    nutrients.add(new Object[] {"Vitamin A (kIU)", 5.0});
    nutrients.add(new Object[] {"Vitamin B1 (mg)", 1.8});
    nutrients.add(new Object[] {"Vitamin B2 (mg)", 2.7});
    nutrients.add(new Object[] {"Niacin (mg)", 18.0});
    nutrients.add(new Object[] {"Vitamin C (mg)", 75.0});

    List<Object[]> data = new ArrayList<>();
    data.add(new Object[] {"Wheat Flour (Enriched)", "10 lb.", 36,
        new double[] {44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0}});
    data.add(new Object[] {
        "Macaroni", "1 lb.", 14.1, new double[] {11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0}});
    data.add(new Object[] {"Wheat Cereal (Enriched)", "28 oz.", 24.2,
        new double[] {11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0}});
    data.add(new Object[] {
        "Corn Flakes", "8 oz.", 7.1, new double[] {11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0}});
    data.add(new Object[] {
        "Corn Meal", "1 lb.", 4.6, new double[] {36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0}});
    data.add(new Object[] {
        "Hominy Grits", "24 oz.", 8.5, new double[] {28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0}});
    data.add(
        new Object[] {"Rice", "1 lb.", 7.5, new double[] {21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0}});
    data.add(new Object[] {
        "Rolled Oats", "1 lb.", 7.1, new double[] {25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0}});
    data.add(new Object[] {"White Bread (Enriched)", "1 lb.", 7.9,
        new double[] {15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0}});
    data.add(new Object[] {"Whole Wheat Bread", "1 lb.", 9.1,
        new double[] {12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0}});
    data.add(new Object[] {
        "Rye Bread", "1 lb.", 9.1, new double[] {12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0}});
    data.add(new Object[] {
        "Pound Cake", "1 lb.", 24.8, new double[] {8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0}});
    data.add(new Object[] {
        "Soda Crackers", "1 lb.", 15.1, new double[] {12.5, 288, 0.5, 50, 0, 0, 0, 0, 0}});
    data.add(
        new Object[] {"Milk", "1 qt.", 11, new double[] {6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177}});
    data.add(new Object[] {"Evaporated Milk (can)", "14.5 oz.", 6.7,
        new double[] {8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60}});
    data.add(
        new Object[] {"Butter", "1 lb.", 30.8, new double[] {10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0}});
    data.add(new Object[] {
        "Oleomargarine", "1 lb.", 16.1, new double[] {20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0}});
    data.add(new Object[] {
        "Eggs", "1 doz.", 32.6, new double[] {2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0}});
    data.add(new Object[] {"Cheese (Cheddar)", "1 lb.", 24.2,
        new double[] {7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0}});
    data.add(new Object[] {
        "Cream", "1/2 pt.", 14.1, new double[] {3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17}});
    data.add(new Object[] {
        "Peanut Butter", "1 lb.", 17.9, new double[] {15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0}});
    data.add(new Object[] {
        "Mayonnaise", "1/2 pt.", 16.7, new double[] {8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0}});
    data.add(new Object[] {"Crisco", "1 lb.", 20.3, new double[] {20.1, 0, 0, 0, 0, 0, 0, 0, 0}});
    data.add(new Object[] {"Lard", "1 lb.", 9.8, new double[] {41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0}});
    data.add(new Object[] {
        "Sirloin Steak", "1 lb.", 39.6, new double[] {2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0}});
    data.add(new Object[] {
        "Round Steak", "1 lb.", 36.4, new double[] {2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0}});
    data.add(
        new Object[] {"Rib Roast", "1 lb.", 29.2, new double[] {3.4, 213, 0.1, 33, 0, 0, 2, 0, 0}});
    data.add(new Object[] {
        "Chuck Roast", "1 lb.", 22.6, new double[] {3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0}});
    data.add(
        new Object[] {"Plate", "1 lb.", 14.6, new double[] {8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0}});
    data.add(new Object[] {"Liver (Beef)", "1 lb.", 26.8,
        new double[] {2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525}});
    data.add(new Object[] {
        "Leg of Lamb", "1 lb.", 27.6, new double[] {3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0}});
    data.add(new Object[] {
        "Lamb Chops (Rib)", "1 lb.", 36.6, new double[] {3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0}});
    data.add(new Object[] {
        "Pork Chops", "1 lb.", 30.7, new double[] {3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0}});
    data.add(new Object[] {
        "Pork Loin Roast", "1 lb.", 24.2, new double[] {4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0}});
    data.add(new Object[] {
        "Bacon", "1 lb.", 25.6, new double[] {10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0}});
    data.add(new Object[] {
        "Ham, smoked", "1 lb.", 27.4, new double[] {6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0}});
    data.add(new Object[] {
        "Salt Pork", "1 lb.", 16, new double[] {18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0}});
    data.add(new Object[] {"Roasting Chicken", "1 lb.", 30.3,
        new double[] {1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46}});
    data.add(new Object[] {
        "Veal Cutlets", "1 lb.", 42.3, new double[] {1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0}});
    data.add(new Object[] {
        "Salmon, Pink (can)", "16 oz.", 13, new double[] {5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0}});
    data.add(new Object[] {
        "Apples", "1 lb.", 4.4, new double[] {5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544}});
    data.add(new Object[] {
        "Bananas", "1 lb.", 6.1, new double[] {4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498}});
    data.add(
        new Object[] {"Lemons", "1 doz.", 26, new double[] {1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952}});
    data.add(new Object[] {
        "Oranges", "1 doz.", 30.9, new double[] {2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998}});
    data.add(new Object[] {
        "Green Beans", "1 lb.", 7.1, new double[] {2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862}});
    data.add(new Object[] {
        "Cabbage", "1 lb.", 3.7, new double[] {2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369}});
    data.add(new Object[] {
        "Carrots", "1 bunch", 4.7, new double[] {2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608}});
    data.add(new Object[] {
        "Celery", "1 stalk", 7.3, new double[] {0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313}});
    data.add(new Object[] {
        "Lettuce", "1 head", 8.2, new double[] {0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449}});
    data.add(new Object[] {
        "Onions", "1 lb.", 3.6, new double[] {5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184}});
    data.add(new Object[] {
        "Potatoes", "15 lb.", 34, new double[] {14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522}});
    data.add(new Object[] {
        "Spinach", "1 lb.", 8.1, new double[] {1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755}});
    data.add(new Object[] {"Sweet Potatoes", "1 lb.", 5.1,
        new double[] {9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912}});
    data.add(new Object[] {"Peaches (can)", "No. 2 1/2", 16.8,
        new double[] {3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196}});
    data.add(new Object[] {
        "Pears (can)", "No. 2 1/2", 20.4, new double[] {3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81}});
    data.add(new Object[] {
        "Pineapple (can)", "No. 2 1/2", 21.3, new double[] {2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399}});
    data.add(new Object[] {"Asparagus (can)", "No. 2", 27.7,
        new double[] {0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272}});
    data.add(new Object[] {
        "Green Beans (can)", "No. 2", 10, new double[] {1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431}});
    data.add(new Object[] {"Pork and Beans (can)", "16 oz.", 7.1,
        new double[] {7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0}});
    data.add(new Object[] {
        "Corn (can)", "No. 2", 10.4, new double[] {5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218}});
    data.add(new Object[] {
        "Peas (can)", "No. 2", 13.8, new double[] {2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370}});
    data.add(new Object[] {
        "Tomatoes (can)", "No. 2", 8.6, new double[] {1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253}});
    data.add(new Object[] {"Tomato Soup (can)", "10 1/2 oz.", 7.6,
        new double[] {1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862}});
    data.add(new Object[] {
        "Peaches, Dried", "1 lb.", 15.7, new double[] {8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57}});
    data.add(new Object[] {
        "Prunes, Dried", "1 lb.", 9, new double[] {12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257}});
    data.add(new Object[] {"Raisins, Dried", "15 oz.", 9.4,
        new double[] {13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136}});
    data.add(new Object[] {
        "Peas, Dried", "1 lb.", 7.9, new double[] {20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0}});
    data.add(new Object[] {"Lima Beans, Dried", "1 lb.", 8.9,
        new double[] {17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0}});
    data.add(new Object[] {"Navy Beans, Dried", "1 lb.", 5.9,
        new double[] {26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0}});
    data.add(new Object[] {"Coffee", "1 lb.", 22.4, new double[] {0, 0, 0, 0, 0, 4, 5.1, 50, 0}});
    data.add(new Object[] {"Tea", "1/4 lb.", 17.4, new double[] {0, 0, 0, 0, 0, 0, 2.3, 42, 0}});
    data.add(
        new Object[] {"Cocoa", "8 oz.", 8.6, new double[] {8.7, 237, 3, 72, 0, 2, 11.9, 40, 0}});
    data.add(new Object[] {
        "Chocolate", "8 oz.", 16.2, new double[] {8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0}});
    data.add(new Object[] {"Sugar", "10 lb.", 51.7, new double[] {34.9, 0, 0, 0, 0, 0, 0, 0, 0}});
    data.add(new Object[] {
        "Corn Syrup", "24 oz.", 13.7, new double[] {14.7, 0, 0.5, 74, 0, 0, 0, 5, 0}});
    data.add(new Object[] {
        "Molasses", "18 oz.", 13.6, new double[] {9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0}});
    data.add(new Object[] {"Strawberry Preserves", "1 lb.", 20.5,
        new double[] {6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0}});


    // Create the linear solver with the GLOP backend.
    MPSolver solver = MPSolver.createSolver("GLOP");
    if (solver == null) {
      System.out.println("Could not create solver GLOP");
      return;
    }

    double infinity = java.lang.Double.POSITIVE_INFINITY;
    List<MPVariable> foods = new ArrayList<>();
    for (int i = 0; i < data.size(); ++i) {
      foods.add(solver.makeNumVar(0.0, infinity, (String) data.get(i)[0]));
    }
    System.out.println("Number of variables = " + solver.numVariables());

    MPConstraint[] constraints = new MPConstraint[nutrients.size()];
    for (int i = 0; i < nutrients.size(); ++i) {
      constraints[i] = solver.makeConstraint(
          (double) nutrients.get(i)[1], infinity, (String) nutrients.get(i)[0]);
      for (int j = 0; j < data.size(); ++j) {
        constraints[i].setCoefficient(foods.get(j), ((double[]) data.get(j)[3])[i]);
      }
      // constraints.add(constraint);
    }
    System.out.println("Number of constraints = " + solver.numConstraints());

    MPObjective objective = solver.objective();
    for (int i = 0; i < data.size(); ++i) {
      objective.setCoefficient(foods.get(i), 1);
    }
    objective.setMinimization();

    final MPSolver.ResultStatus resultStatus = solver.solve();

    // Check that the problem has an optimal solution.
    if (resultStatus != MPSolver.ResultStatus.OPTIMAL) {
      System.err.println("The problem does not have an optimal solution!");
      if (resultStatus == MPSolver.ResultStatus.FEASIBLE) {
        System.err.println("A potentially suboptimal solution was found.");
      } else {
        System.err.println("The solver could not solve the problem.");
        return;
      }
    }

    // Display the amounts (in dollars) to purchase of each food.
    double[] nutrientsResult = new double[nutrients.size()];
    System.out.println("\nAnnual Foods:");
    for (int i = 0; i < foods.size(); ++i) {
      if (foods.get(i).solutionValue() > 0.0) {
        System.out.println((String) data.get(i)[0] + ": $" + 365 * foods.get(i).solutionValue());
        for (int j = 0; j < nutrients.size(); ++j) {
          nutrientsResult[j] += ((double[]) data.get(i)[3])[j] * foods.get(i).solutionValue();
        }
      }
    }
    System.out.println("\nOptimal annual price: $" + 365 * objective.value());

    System.out.println("\nNutrients per day:");
    for (int i = 0; i < nutrients.size(); ++i) {
      System.out.println(
          nutrients.get(i)[0] + ": " + nutrientsResult[i] + " (min " + nutrients.get(i)[1] + ")");
    }

    System.out.println("\nAdvanced usage:");
    System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
    System.out.println("Problem solved in " + solver.iterations() + " iterations");
  }

  private StiglerDiet() {}
}

С#

// The Stigler diet problem.
using System;
using System.Collections.Generic;
using Google.OrTools.LinearSolver;

public class StiglerDiet
{
    static void Main()
    {
        // Nutrient minimums.
        (String Name, double Value)[] nutrients =
            new[] { ("Calories (kcal)", 3.0), ("Protein (g)", 70.0),    ("Calcium (g)", 0.8),
                    ("Iron (mg)", 12.0),      ("Vitamin A (kIU)", 5.0), ("Vitamin B1 (mg)", 1.8),
                    ("Vitamin B2 (mg)", 2.7), ("Niacin (mg)", 18.0),    ("Vitamin C (mg)", 75.0) };

        (String Name, String Unit, double Price, double[] Nutrients)[] data = new[] {
            ("Wheat Flour (Enriched)", "10 lb.", 36, new double[] { 44.7, 1411, 2, 365, 0, 55.4, 33.3, 441, 0 }),
            ("Macaroni", "1 lb.", 14.1, new double[] { 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0 }),
            ("Wheat Cereal (Enriched)", "28 oz.", 24.2, new double[] { 11.8, 377, 14.4, 175, 0, 14.4, 8.8, 114, 0 }),
            ("Corn Flakes", "8 oz.", 7.1, new double[] { 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0 }),
            ("Corn Meal", "1 lb.", 4.6, new double[] { 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106, 0 }),
            ("Hominy Grits", "24 oz.", 8.5, new double[] { 28.6, 680, 0.8, 80, 0, 10.6, 1.6, 110, 0 }),
            ("Rice", "1 lb.", 7.5, new double[] { 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0 }),
            ("Rolled Oats", "1 lb.", 7.1, new double[] { 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0 }),
            ("White Bread (Enriched)", "1 lb.", 7.9, new double[] { 15.0, 488, 2.5, 115, 0, 13.8, 8.5, 126, 0 }),
            ("Whole Wheat Bread", "1 lb.", 9.1, new double[] { 12.2, 484, 2.7, 125, 0, 13.9, 6.4, 160, 0 }),
            ("Rye Bread", "1 lb.", 9.1, new double[] { 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0 }),
            ("Pound Cake", "1 lb.", 24.8, new double[] { 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0 }),
            ("Soda Crackers", "1 lb.", 15.1, new double[] { 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0 }),
            ("Milk", "1 qt.", 11, new double[] { 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177 }),
            ("Evaporated Milk (can)", "14.5 oz.", 6.7, new double[] { 8.4, 422, 15.1, 9, 26, 3, 23.5, 11, 60 }),
            ("Butter", "1 lb.", 30.8, new double[] { 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0 }),
            ("Oleomargarine", "1 lb.", 16.1, new double[] { 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0 }),
            ("Eggs", "1 doz.", 32.6, new double[] { 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0 }),
            ("Cheese (Cheddar)", "1 lb.", 24.2, new double[] { 7.4, 448, 16.4, 19, 28.1, 0.8, 10.3, 4, 0 }),
            ("Cream", "1/2 pt.", 14.1, new double[] { 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17 }),
            ("Peanut Butter", "1 lb.", 17.9, new double[] { 15.7, 661, 1.0, 48, 0, 9.6, 8.1, 471, 0 }),
            ("Mayonnaise", "1/2 pt.", 16.7, new double[] { 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0 }),
            ("Crisco", "1 lb.", 20.3, new double[] { 20.1, 0, 0, 0, 0, 0, 0, 0, 0 }),
            ("Lard", "1 lb.", 9.8, new double[] { 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0 }),
            ("Sirloin Steak", "1 lb.", 39.6, new double[] { 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9, 69, 0 }),
            ("Round Steak", "1 lb.", 36.4, new double[] { 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0 }),
            ("Rib Roast", "1 lb.", 29.2, new double[] { 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0 }),
            ("Chuck Roast", "1 lb.", 22.6, new double[] { 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0 }),
            ("Plate", "1 lb.", 14.6, new double[] { 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0 }),
            ("Liver (Beef)", "1 lb.", 26.8, new double[] { 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8, 316, 525 }),
            ("Leg of Lamb", "1 lb.", 27.6, new double[] { 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0 }),
            ("Lamb Chops (Rib)", "1 lb.", 36.6, new double[] { 3.3, 140, 0.1, 15, 0, 1.7, 2.7, 54, 0 }),
            ("Pork Chops", "1 lb.", 30.7, new double[] { 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0 }),
            ("Pork Loin Roast", "1 lb.", 24.2, new double[] { 4.4, 249, 0.3, 37, 0, 18.2, 3.6, 79, 0 }),
            ("Bacon", "1 lb.", 25.6, new double[] { 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0 }),
            ("Ham, smoked", "1 lb.", 27.4, new double[] { 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0 }),
            ("Salt Pork", "1 lb.", 16, new double[] { 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0 }),
            ("Roasting Chicken", "1 lb.", 30.3, new double[] { 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8, 68, 46 }),
            ("Veal Cutlets", "1 lb.", 42.3, new double[] { 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0 }),
            ("Salmon, Pink (can)", "16 oz.", 13, new double[] { 5.8, 705, 6.8, 45, 3.5, 1, 4.9, 209, 0 }),
            ("Apples", "1 lb.", 4.4, new double[] { 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544 }),
            ("Bananas", "1 lb.", 6.1, new double[] { 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498 }),
            ("Lemons", "1 doz.", 26, new double[] { 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952 }),
            ("Oranges", "1 doz.", 30.9, new double[] { 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998 }),
            ("Green Beans", "1 lb.", 7.1, new double[] { 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862 }),
            ("Cabbage", "1 lb.", 3.7, new double[] { 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369 }),
            ("Carrots", "1 bunch", 4.7, new double[] { 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608 }),
            ("Celery", "1 stalk", 7.3, new double[] { 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313 }),
            ("Lettuce", "1 head", 8.2, new double[] { 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449 }),
            ("Onions", "1 lb.", 3.6, new double[] { 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184 }),
            ("Potatoes", "15 lb.", 34, new double[] { 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198, 2522 }),
            ("Spinach", "1 lb.", 8.1, new double[] { 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755 }),
            ("Sweet Potatoes", "1 lb.", 5.1, new double[] { 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4, 83, 1912 }),
            ("Peaches (can)", "No. 2 1/2", 16.8, new double[] { 3.7, 20, 0.4, 10, 21.5, 0.5, 1, 31, 196 }),
            ("Pears (can)", "No. 2 1/2", 20.4, new double[] { 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5, 81 }),
            ("Pineapple (can)", "No. 2 1/2", 21.3, new double[] { 2.4, 16, 0.4, 8, 2, 2.8, 0.8, 7, 399 }),
            ("Asparagus (can)", "No. 2", 27.7, new double[] { 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1, 17, 272 }),
            ("Green Beans (can)", "No. 2", 10, new double[] { 1.0, 54, 2, 65, 53.9, 1.6, 4.3, 32, 431 }),
            ("Pork and Beans (can)", "16 oz.", 7.1, new double[] { 7.5, 364, 4, 134, 3.5, 8.3, 7.7, 56, 0 }),
            ("Corn (can)", "No. 2", 10.4, new double[] { 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218 }),
            ("Peas (can)", "No. 2", 13.8, new double[] { 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37, 370 }),
            ("Tomatoes (can)", "No. 2", 8.6, new double[] { 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5, 36, 1253 }),
            ("Tomato Soup (can)", "10 1/2 oz.", 7.6, new double[] { 1.6, 71, 0.6, 43, 57.9, 3.5, 2.4, 67, 862 }),
            ("Peaches, Dried", "1 lb.", 15.7, new double[] { 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3, 55, 57 }),
            ("Prunes, Dried", "1 lb.", 9, new double[] { 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65, 257 }),
            ("Raisins, Dried", "15 oz.", 9.4, new double[] { 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4, 24, 136 }),
            ("Peas, Dried", "1 lb.", 7.9, new double[] { 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4, 162, 0 }),
            ("Lima Beans, Dried", "1 lb.", 8.9, new double[] { 17.4, 1055, 3.7, 459, 5.1, 26.9, 38.2, 93, 0 }),
            ("Navy Beans, Dried", "1 lb.", 5.9, new double[] { 26.9, 1691, 11.4, 792, 0, 38.4, 24.6, 217, 0 }),
            ("Coffee", "1 lb.", 22.4, new double[] { 0, 0, 0, 0, 0, 4, 5.1, 50, 0 }),
            ("Tea", "1/4 lb.", 17.4, new double[] { 0, 0, 0, 0, 0, 0, 2.3, 42, 0 }),
            ("Cocoa", "8 oz.", 8.6, new double[] { 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0 }),
            ("Chocolate", "8 oz.", 16.2, new double[] { 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0 }),
            ("Sugar", "10 lb.", 51.7, new double[] { 34.9, 0, 0, 0, 0, 0, 0, 0, 0 }),
            ("Corn Syrup", "24 oz.", 13.7, new double[] { 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0 }),
            ("Molasses", "18 oz.", 13.6, new double[] { 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0 }),
            ("Strawberry Preserves", "1 lb.", 20.5, new double[] { 6.4, 11, 0.4, 7, 0.2, 0.2, 0.4, 3, 0 })
        };

        // Create the linear solver with the GLOP backend.
        Solver solver = Solver.CreateSolver("GLOP");
        if (solver is null)
        {
            return;
        }

        List<Variable> foods = new List<Variable>();
        for (int i = 0; i < data.Length; ++i)
        {
            foods.Add(solver.MakeNumVar(0.0, double.PositiveInfinity, data[i].Name));
        }
        Console.WriteLine($"Number of variables = {solver.NumVariables()}");

        List<Constraint> constraints = new List<Constraint>();
        for (int i = 0; i < nutrients.Length; ++i)
        {
            Constraint constraint =
                solver.MakeConstraint(nutrients[i].Value, double.PositiveInfinity, nutrients[i].Name);
            for (int j = 0; j < data.Length; ++j)
            {
                constraint.SetCoefficient(foods[j], data[j].Nutrients[i]);
            }
            constraints.Add(constraint);
        }
        Console.WriteLine($"Number of constraints = {solver.NumConstraints()}");

        Objective objective = solver.Objective();
        for (int i = 0; i < data.Length; ++i)
        {
            objective.SetCoefficient(foods[i], 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!");
            if (resultStatus == Solver.ResultStatus.FEASIBLE)
            {
                Console.WriteLine("A potentially suboptimal solution was found.");
            }
            else
            {
                Console.WriteLine("The solver could not solve the problem.");
                return;
            }
        }

        // Display the amounts (in dollars) to purchase of each food.
        double[] nutrientsResult = new double[nutrients.Length];
        Console.WriteLine("\nAnnual Foods:");
        for (int i = 0; i < foods.Count; ++i)
        {
            if (foods[i].SolutionValue() > 0.0)
            {
                Console.WriteLine($"{data[i].Name}: ${365 * foods[i].SolutionValue():N2}");
                for (int j = 0; j < nutrients.Length; ++j)
                {
                    nutrientsResult[j] += data[i].Nutrients[j] * foods[i].SolutionValue();
                }
            }
        }
        Console.WriteLine($"\nOptimal annual price: ${365 * objective.Value():N2}");

        Console.WriteLine("\nNutrients per day:");
        for (int i = 0; i < nutrients.Length; ++i)
        {
            Console.WriteLine($"{nutrients[i].Name}: {nutrientsResult[i]:N2} (min {nutrients[i].Value})");
        }

        Console.WriteLine("\nAdvanced usage:");
        Console.WriteLine($"Problem solved in {solver.WallTime()} milliseconds");
        Console.WriteLine($"Problem solved in {solver.Iterations()} iterations");
    }
}