Перейти к основному содержимому

Задача о рюкзаке (многомерная)

В предыдущем примере мы рассмотрели классическую одномерную задачу о рюкзаке. В этом примере рассматривается многомерная версия задачи, в которой, помимо ограничения по весу, добавляется ограничение по объему. Это ключевое отличие от классической одномерной модели - остальная структура и логика остаются без изменений.

Постановка задачи

  • Имеется 50 предметов. У каждого задана ценность, вес и объем в целочисленных единицах;
  • Максимально допустимый вес рюкзака — 850 единиц;
  • Объем рюкзака — 700 единиц;
  • Необходимо выбрать такие предметы, чтобы их общая ценность была максимальной, при этом суммарный вес и объем не превышали лимиты.

Решение задачи

Далее поэтапно рассмотрим, как реализовать решение этой задачи с использованием библиотеки О2.

1. Выбор модели

Для подобных задач в О2 предусмотрена специальная модель — МодельЗадачиРюкзака. Эта модель работает только с целыми числами, как того требует классическая формулировка задачи.

2. Создание объекта модели

Инициализируется многомерная модель задачи о рюкзаке через создание параметров модели с указанием размерности.

// Создание многомерной модели задачи рюкзака
ПараметрыМодели = О2
.Модели()
.МодельЗадачиРюкзака()
.СоздатьПараметрыМодели();

ПараметрыМодели.Размерность = 2; // <-- указываем размерность модели

Модель = О2.СоздатьМодель(
О2.ТипыМоделей().МодельЗадачиРюкзака(),
ПараметрыМодели
);

3. Ввод данных

Данные по задаче включают в себя массивы ценностей, весов и объемов для всех доступных предметов. Ценности определяют полезность каждого предмета, а веса и объемы - затраты места в рюкзаке.

// Вводим данные
МаксимальныйВес = 850;
МаксимальныйОбъем = 700;

// Данные подбираемых предметов
Ценности = О2.Утилиты().МассивЧиселИзСтроки(
"360, 83, 59, 130, 431, 67, 230, 52, 93, 125,
|670, 892, 600, 38, 48, 147, 78, 256, 63, 17,
|120, 164, 432, 35, 92, 110, 22, 42, 50, 323,
|514, 28, 87, 73, 78, 15, 26, 78, 210, 36,
|85, 189, 274, 43, 33, 10, 19, 389, 276, 312"
);

Веса = О2.Утилиты().МассивЧиселИзСтроки(
"7, 0, 30, 22, 80, 94, 11, 81, 70, 64,
|59, 18, 0, 36, 3, 8, 15, 42, 9, 0,
|42, 47, 52, 32, 26, 48, 55, 6, 29, 84,
|2, 4, 18, 56, 7, 29, 93, 44, 71, 3,
|86, 66, 31, 65, 0, 79, 20, 65, 52, 13"
);

Объемы = О2.Утилиты().МассивЧиселИзСтроки(
"15, 10, 25, 18, 45, 60, 12, 55, 40, 35,
|30, 22, 8, 28, 5, 14, 20, 38, 12, 6,
|32, 41, 48, 26, 21, 44, 50, 9, 24, 65,
|7, 11, 16, 46, 13, 31, 70, 39, 52, 8,
|61, 49, 27, 58, 3, 68, 19, 56, 43, 17"
);

4. Установка ограничений

Установим максимальный вес и объем рюкзака.

// Устанавливаем ограничения по каждому измерению
Модель.Ограничения().Установить(
О2.Утилиты().Массив(МаксимальныйВес, МаксимальныйОбъем)
);

5. Добавление элементов

Для каждого премета создадим элемент модели. Элемент содержит информацию о ценности, весе и объеме предмета.

// Регистрируем элементы модели
Предметы = Новый Массив;
Для К = 0 По Ценности.ВГраница() Цикл
Предмет = Модель.Элемент(
Ценности[К],
О2.Утилиты().Массив(Веса[К], Объемы[К]) // <-- массив затрат по каждому измерению модели
);
Предметы.Добавить(Предмет);
КонецЦикла;

6. Решение модели

Для получения решения достаточно вызвать метод Решить объекта модели.

// Вызов решателя
Решение = Модель.Решить();

7. Вывод результатов

// Вывод результатов
СтатусРешения = Решение.Статус(); // "Оптимальное" или "Допустимое"
СуммарнаяЦенность = Решение.Ценность(); // значение целевой функции
КоличествоЭлементов = Решение.КоличествоЭлементов(); // количество элементов в рюкзаке

Сообщить("Статус решения: " + СтатусРешения);
Сообщить("Использовано элементов: " + КоличествоЭлементов);
Сообщить("Суммарная ценность: " + СуммарнаяЦенность);

Сообщить("Использованы следующие элементы:" + Символы.ПС);

ОбщийВес = 0;
ОбщийОбъем = 0;
Для К = 0 По Предметы.ВГраница() Цикл
Предмет = Предметы[К];
ЭлементПрисутствует = Решение.ЭлементПрисутствует(Предмет);

Если ЭлементПрисутствует Тогда
ОбщийВес = ОбщийВес + Веса[К];
ОбщийОбъем = ОбщийОбъем + Объемы[К];

Сообщить(СтрШаблон(
" Предмет №%1: ценность=%2, вес=%3, объем=%4",
Формат(К + 1, "ЧГ=0"),
Ценности[К],
Веса[К],
Объемы[К]
));
КонецЕсли;
КонецЦикла;

Сообщить(СтрШаблон(
"Общий вес использованных элементов: %1 из %2",
ОбщийВес,
МаксимальныйВес
));

Сообщить(СтрШаблон(
"Общий объем использованных элементов: %1 из %2",
ОбщийОбъем,
МаксимальныйОбъем
));

Полный код решения задачи

Ниже представлен полный код решения. Вы также можете скачать пример в виде готовой обработки.

// Создание многомерной модели задачи рюкзака
МенеджерМоделей = О2
.Модели()
.МодельЗадачиРюкзака();

ПараметрыМодели = МенеджерМоделей.СоздатьПараметрыМодели();

ПараметрыМодели.Размерность = 2;

Модель = МенеджерМоделей.СоздатьМодель(ПараметрыМодели);

// Вводим данные
МаксимальныйВес = 850;
МаксимальныйОбъем = 700;

// Данные подбираемых предметов
Ценности = О2.Утилиты().МассивЧиселИзСтроки(
"360, 83, 59, 130, 431, 67, 230, 52, 93, 125,
|670, 892, 600, 38, 48, 147, 78, 256, 63, 17,
|120, 164, 432, 35, 92, 110, 22, 42, 50, 323,
|514, 28, 87, 73, 78, 15, 26, 78, 210, 36,
|85, 189, 274, 43, 33, 10, 19, 389, 276, 312"
);

Веса = О2.Утилиты().МассивЧиселИзСтроки(
"7, 0, 30, 22, 80, 94, 11, 81, 70, 64,
|59, 18, 0, 36, 3, 8, 15, 42, 9, 0,
|42, 47, 52, 32, 26, 48, 55, 6, 29, 84,
|2, 4, 18, 56, 7, 29, 93, 44, 71, 3,
|86, 66, 31, 65, 0, 79, 20, 65, 52, 13"
);

Объемы = О2.Утилиты().МассивЧиселИзСтроки(
"15, 10, 25, 18, 45, 60, 12, 55, 40, 35,
|30, 22, 8, 28, 5, 14, 20, 38, 12, 6,
|32, 41, 48, 26, 21, 44, 50, 9, 24, 65,
|7, 11, 16, 46, 13, 31, 70, 39, 52, 8,
|61, 49, 27, 58, 3, 68, 19, 56, 43, 17"
);

// Устанавливаем ограничения по каждому измерению
Модель.Ограничения().Установить(
О2.Утилиты().Массив(МаксимальныйВес, МаксимальныйОбъем)
);

// Регистрируем элементы модели
Предметы = Новый Массив;
Для К = 0 По Ценности.ВГраница() Цикл
Предмет = Модель.Элемент(
Ценности[К],
О2.Утилиты().Массив(Веса[К], Объемы[К])
);
Предметы.Добавить(Предмет);
КонецЦикла;

// Запускаем поиск решения
Решение = Модель.Решить();

// Выводим результаты
СтатусРешения = Решение.Статус(); // "Оптимальное" или "Допустимое"
СуммарнаяЦенность = Решение.Ценность(); // значение целевой функции
КоличествоЭлементов = Решение.КоличествоЭлементов(); // количество элементов в рюкзаке

Сообщить("Статус решения: " + СтатусРешения);
Сообщить("Использовано элементов: " + КоличествоЭлементов);
Сообщить("Суммарная ценность: " + СуммарнаяЦенность);

Сообщить("Использованы следующие элементы:" + Символы.ПС);

ОбщийВес = 0;
ОбщийОбъем = 0;
Для К = 0 По Предметы.ВГраница() Цикл
Предмет = Предметы[К];
ЭлементПрисутствует = Решение.ЭлементПрисутствует(Предмет);

Если ЭлементПрисутствует Тогда
ОбщийВес = ОбщийВес + Веса[К];
ОбщийОбъем = ОбщийОбъем + Объемы[К];

Сообщить(СтрШаблон(
" Предмет №%1: ценность=%2, вес=%3, объем=%4",
Формат(К + 1, "ЧГ=0"),
Ценности[К],
Веса[К],
Объемы[К]
));
КонецЕсли;
КонецЦикла;

Сообщить(СтрШаблон(
"Общий вес использованных элементов: %1 из %2",
ОбщийВес,
МаксимальныйВес
));

Сообщить(СтрШаблон(
"Общий объем использованных элементов: %1 из %2",
ОбщийОбъем,
МаксимальныйОбъем
));
  Скачать пример