Применение генератора бинарных массивов к решению прикладных задач



Скачать 80.09 Kb.
НазваниеПрименение генератора бинарных массивов к решению прикладных задач
Дата28.10.2013
Размер80.09 Kb.
ТипРешение
источник

Мендель В.В., ФГБОУ ВПО ДВГГУ

Готсдинер Г.Я., МБОУ «Математический лицей»


Применение генератора бинарных массивов к решению прикладных задач

Массивы – один из наиболее простых стандартных типов данных, используемых в большинстве языков программирования. Однако эта «простота» не мешает применять данный тип данных при решении достаточно сложных задач. Одну из таких задач – задачу об упаковке рюкзака – мы рассмотрим в данной статье.


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

У туриста имеется набор предметов, которые могут быть полезными в походе. Для каждого предмета определена (в баллах) его полезность. Кроме того, каждый предмет имеет некоторую массу. Грузоподъемность рюкзака ограничена некоторым числом, превысить которое нельзя. Требуется упаковать предметы в рюкзак так, чтобы их суммарная полезность была наибольшей, а суммарная масса не превысила максимальную грузоподъёмность.

Данная задача относится к, так называемым, трудно решаемым проблемам. Это означает, что точные алгоритмы ее решения являются «переборными» и имеют высокую трудоемкость.

При определенных ограничениях удается применять более «быстрые» алгоритмы, но, для некоторых комбинаций входных значений, они тоже работают долго, а в некоторых случаях и вовсе не дают результата (не могут найти решение при заданных начальных условиях).


^ Описание алгоритма

Решение задачи при любом конечном наборе предметов можно получить следующим образом:

- Первоначально за оптимальное текущее значение суммарной полезности берется ноль.

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

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

- Если суммарный вес оказывается в пределах допустимого, то тогда суммарная полезность сравнивается с текущей оптимальной. Если она не больше текущей оптимальной, то выполняется переход к следующей комбинации, если больше, тогда она становится текущей оптимальной, а текущая комбинация сохраняется как текущая оптимальная. После этого выполняется переход к следующей комбинации.

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


Как было сказано выше, этот алгоритм является переборным. Для его выполнения, в случае, когда дано ^ N0 предметов, потребуется рассмотреть 2N0-1 комбинацию (для 20 предметов число комбинаций превысит миллион, а для 30 - миллиард). Тем не менее, современные компьютеры позволяют довольно быстро сгенерировать и проанализировать все возможные варианты даже при относительно большом количестве предметов. Поэтому перейдем к задаче генерирования всевозможных комбинаций из предметов.


^ Генетический код подмножества

Проясним используемую терминологию. Пусть имеется некоторое множество и пусть - его подмножество. Рассмотрим массив , состоящий из нулей и единиц. Если в этом массиве положить , а остальные элементы считать равными нулю, то мы получим генетический код подмножества B.

Таким образом, генетический код подмножества, это массив из нулей и единиц (массивы такого вида часто называют бинарными). Причем единицы расположены только на тех местах, которые соответствуют номерам элементов множества A, включенным в подмножество B.

Примеры

1. Пусть . Генетический код множества A состоит только из единиц (включены все элементы): .

2. Генетический код пустого множества состоит только из нулей (не выбран ни один из элементов): .

3. Множеству соответствует код .

Очевидно, что любой массив из нулей и единиц однозначно порождает подмножество и у каждого подмножества имеется только один генетический код. Общее количество бинарных (состоящих из нулей и единиц) массивов длины N0 равно 2N0, что равно общему числу подмножеств данного множества. Так как пустое множество рассматривать бессмысленно, мы получаем общее число возможных комбинаций для упаковки, равное 2N0-1.


Алгоритм порождения всех бинарных массивов заданной длины

Предлагаемый в статье алгоритм порождения всех бинарных массивов заданной длины аналогичен популярному в теории алгоритмов приему вычисления функции следования в двоичной системе счисления.

Прибавление единицы в двоичной системе организовано так:

1. Ищется конец слова, являющегося двоичной записью числа.

2. От конца слова в начало пошагово рассматриваются символы: до тех пор, пока не встречен ноль, при этом все единицы заменяют на нули, а первый встреченный ноль заменяют на единицу и процесс останавливается.

В нашей ситуации удобно начинать с начала «слова» - первого элемента бинарного массива. До тех пор, пока не встречен элемент массива, равный нулю, все текущие значения, равные единице, заменяются на нули. Первое встреченное значение в массиве, равное нулю, заменяется на единицу. Получаем новый генетический код!

Некоторую проблему в данном алгоритме представляет правило остановки: как определить, что все генетические коды уже рассмотрены?

В предложенном алгоритме остановка должна произойти, когда все элементы массива равны единице. Это можно обусловить по-разному: считать сумму элементов и сравнивать ее с числом N0, или считать произведение элементов и сравнивать его с единицей.

Мы используем другой прием: добавим к массиву еще один (N0+1) элемент. Обращение этого элемента в единицу как раз будет означать, что для предыдущих N0 элементов рассмотрены все возможные комбинации.

Ниже приводится листинг программы, генерирующей и выводящей на экран все варианты генетического кода – бинарные массивы заданной длины.

program int2bin;1 {программа для генерирования всех возможных бинарных массивов длины N0}

const

N0 = 10; {количество элементов в массиве}

var

i, j, k: integer; {индексы}

b: array [1..N0 + 1] of integer; {массив бинарного кода}

begin

for i := 1 to N0 + 1 do {инициализация массива (заполнение нулями)}

b[i] := 0;

while b[N0 + 1] = 0 do {проверка условия, что сгенерированы не все коды}

begin

j := 1;

while b[j] > 0 do {поиск в текущем коде первого нулевого элемента

для прибавления единицы}

begin

b[j] := 0; {замена идущих подряд от начала единиц нулями}

j := j + 1;

end;

b[j] := 1; {завершение прибавления единицы - первый

встреченный 0 меняем на 1}

end;

writeln();

for k := 1 to N0 do {печать текущего генетического кода}

write(b[k],’ ‘);

end.

^ Реализация алгоритма оптимальной упаковки рюкзака

Теперь, когда нами создан генератор бинарных кодов, применим его к поиску оптимальной упаковки рюкзака. Ниже приведен листинг программы на языке Pascal.

program Knapsac; {программа упаковки рюкзака предметами данной

ценности и известной массы}

const

N0 = 8; {количество элементов в массиве}

Mmax = 32; {максимальный вес рюкзака}

var

i, j, k: integer; {индексы}

Mit, Zit, Mtek, Ztek: longint; {текущие значения массы и ценности выборки}

b, b0: array [1..N0 + 1] of integer; {текущие исследуемый и оптимальный

генетические коды}

zena, m: array [1..N0] of integer; {массивы, определяющие ценность и

вес предметов}

begin {начало программы}

for i := 1 to N0 + 1 do {инициализация бинарного массива

(заполнение нулями)}

b[i] := 0;

b0 := b;

{задание значений веса и ценности предметов}

zena[1] := 21;zena[2] := 2;zena[3] := 1;zena[4] := 11;zena[5] := 3;zena[6] := 5;zena[7] := 9;zena[8] := 23;

m[1] := 2; m[2] := 1; m[3] := 4; m[4] := 5; m[5] := 7; m[6] := 2; m[7] := 3; m[8] := 31;

Mtek := 0; Ztek := 0; {сброс счетчиков лучших текущего веса и

текущей ценности выборки предметов}

{^ НАЧАЛО ВЫЧИСЛЕНИЙ}

while b[N0 + 1] = 0 do {проверка условия, что сгенерированы не все коды}

begin

j := 1;

while b[j] > 0 do {поиск в текущем коде первого нулевого элемента

для прибавления единицы}

begin

b[j] := 0; {замена идущих подряд от начала единиц нулями}

j := j + 1;

end;

b[j] := 1; {завершение прибавления единицы – первый

встреченный 0 меняем на 1}

Mit := 0; Zit := 0;

for k := 1 to N0 do

begin

Mit := Mit + m[k] * b[k];

Zit := Zit + zena[k] * b[k];

end;

if (Mit < Mmax) and (Zit > Ztek) then

begin

Mtek := Mit;

Ztek := Zit;

b0 := b;

end;

end;

{^ Вывод на экран результатов поиска}

writeln('максимальная масса =', Mtek);

writeln('максимальная цена =', Ztek);

for i := 1 to N0 do

if b0[i] = 1 then

begin

writeln('предмет', i, '=', m[i], ' по цене ', zena[i]);

end;

end.

^ Задания для самостоятельного решения

Предлагаемые здесь задания являются контрольной работой №2 для учащихся 8-11 классов. Решите эти задания, запишите решения в отдельную (от физики и математике) тетрадь. Укажите на обложке следующую информацию о себе:

1. Фамилия, имя, класс, профиль класса (например: Сидоров Василий,10 кл., математический)

2. Индекс, адрес места жительства, электронная почта (если есть), телефон (домашний или мобильный)

3. Данные о школе (например: МБОУ №1 п. Бикин)

4. Фамилия, И. О. учителя информатики (например: учитель информатики Петрова М.И.)

Вы также можете прислать решения по электронной почте на адрес:

kstt@rambler.ru


Задание 1. Доработайте предложенную в статье программу упаковки рюкзака:

1.1. Преобразуйте часть кода программы, генерирующую бинарные массивы в процедуру или функцию и напишите новую программу, использующую эту процедуру.

1.2. Модернизируйте программу так, чтобы исходные данные считывались из файла inp.txt, а результаты сохранялись в файл out.txt. Форматы этих файлов можете установить самостоятельно, но обязательно в сопроводительной записке опишите эти форматы.


Задание 2. Напишите программу, решающую следующую версию проблемы упаковки рюкзака:

В рюкзак помещают два вида вещей – продукты и снаряжение. Максимальный вес рюкзака ограничен числом Mmax. Кроме этого, и для продуктов и для снаряжения установлены минимальные значения полезности Pv и Ps. Нужно упаковать рюкзак, обеспечив при этом максимальную полезность груза. Причем суммарная полезность выбранных продуктов и суммарная полезность выбранного снаряжения не должны быть меньше Pv и Ps соответственно.

Желаем удачи!



1 В TurboPASCAL для корректного вывода данных на экран может потребоваться подключение модуля CRT, для этого после заголовка с новой строки введите текст: USES CRT;

Добавить документ в свой блог или на сайт


Похожие:



Если Вам понравился наш сайт, Вы можеть разместить кнопку на своём сайте или блоге:
refdt.ru


©refdt.ru 2000-2013
условием копирования является указание активной ссылки
обратиться к администрации
refdt.ru