Лекция 9 Жадные алгоритмы

Preview:

Citation preview

Анализ комбинаторных алгоритмов

Лекция №9Жадные алгоритмы

Жадные алгоритмы

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

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

Задача о выборе заявок

Пусть даны n заявок на проведение занятий в аудитории.

Два разных занятия в аудитории не могут перекрываться во времени.

В каждой заявке указаны время начала и время конца занятия (s и f ).

Разные заявки могут перекрываться и тогда можно удовлетворить только одну из них.

Задача о выборе заявок

Заявки i и j совместны, если интервалы [si,fi) и [sj,fj) не пересекаются (fi <= sj или fj <= si).

Задача о выборе заявок состоит в том, чтобы набрать максимальное количество совместных друг с другом заявок.

Задача о выборе заявок

Жадный алгоритм работает в два этапа:

Сортирует заявки по возрастанию времени окончания занятия.

Выбирает первую заявку. После этого выбирает первую совместную с выбранной на предыдущем шаге заявку.

Задача о выборе заявок

void GreedyActivitySelector(s,f){ n = length(s); A->Add(1); j = 1; for (i=2; i<=n; i++) { if (s[i]>=f[j]){ A->Add(i); j = i; } }}

1 2 3 4 5 6 7 8 9 10 11 12

1

23

54

67

8

Задача о выборе заявок

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

Жадный алгоритм дает оптимальное решение не для всех задач.

Применимость жадных алгоритмов

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

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

Принцип оптимальности для подзадач. Оптимальное решение задачи содержит в себе оптимальные решения подзадач.

Применимость жадных алгоритмов

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

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

Применимость жадных алгоритмов

Дискретная задача о рюкзакеПусть вор пробрался на склад, на котором хранится n вещей. Вещь с номером I стоит v рублей весит w килограмм. Максимальный вес, который он может унести, равен W. Вещи ломать и дробить нельзя. Какие вещи должен положить в рюкзак вор, чтобы получить больше денег?

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

Применимость жадных алгоритмов

Обе задачи обладают свойством оптимальности для подзадач. Вынув вещь j из оптимально загруженного рюкзака, получим решение для подзадачи с максимальным весом W- wj и набором из n-1 вещей. Аналогично для непрерывной задачи.

Жадный алгоритм дает оптимальное решение для непрерывной задачи, но не дает для дискретной.

Применимость жадных алгоритмов

5 кг

10 кг

7 кг

Непрерывная задача

30 $/кг

20 $/кг

10 $/кг

5

1017

1020

30

6 $/кг 5 $/кг 4 $/кг

50

10

20

20

$160 $220

30

Дискретная задача

Коды Хаффмана

Для сжатия информации широко используются коды Хаффмана.

Степень сжатия информации с помощью кода Хаффмана составляет 20 - 90%, в зависимости от типа сжимаемой информации.

Алгоритм Хаффмана находит оптимальные коды символов (исходя из частоты их использования в тексте) с помощью жадного выбора.

Коды Хаффмана

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

двоичным кодом (конечной последовательностью бит, называемых словом).

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

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

Коды Хаффмана

a b c d e f

Частоты в тыс. 45 13 12 16 9 5

Равномерный код 000 001 010 011 100 101

Неравномерный код 0 101 100 111 1101 1100

Для файла из 100 000 символов размер будет составлять:При равномерном кодировании: 100 000 * 3 = 300 000При неравномерном кодировании: (45*1+13*3+12*3+16*3+9*4+5*4)*1000 = 224 000

Коды Хаффмана

0 1

0 1 0

a b c d e f

0 0 01 1 1

0 1

1

10a

e

d

f

c b

0

0

110

Коды Хаффмана

Для того чтобы декодирование неравномерного кода можно было однозначно осуществить слева направо, код должен быть префиксным.

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

Для эффективной реализации декодирования можно представить код в виде двоичного дерева, листьями которого являются символы.

Оптимальный код будет представлен деревом, у которого каждая вершина (кроме листьев) имеет двух детей.

Коды Хаффмана

Хаффман построил жадный алгоритм строящий оптимальный префиксный код (код Хаффмана).

Алгоритм строит двоичное дерево кода, снизу вверх, начиная с листьев и делая n-1 «слияний».

В результате слияния получается внутренняя вершина, частота которой равна сумме частот сливаемых объектов.

Коды Хаффмана

f:5 e:9 c:12 b:13 d:16 a:45

f:5 e:9

c:12 b:13 d:16 a:4514

Шаг 1

Шаг 2

Коды Хаффмана

f:5 e:9 c:12 b:13

d:16 a:4514

Шаг 3

25

f:5 e:9

c:12 b:13 d:16

a:45

14

Шаг 4

25 30

Коды Хаффмана

f:5 e:9

c:12 b:13 d:16

a:45

14

Шаг 5

25 30

55

Коды Хаффмана

f:5 e:9

c:12 b:13 d:16

a:45

14

Шаг 6

25 30

55

1000 1

0

0 0

0

1

1

1

Коды Хаффмана

void Huffman(C){ n = length(C); Q->Create(C); for (i=1; i<n; i++) {

z = new NODE;x = Q->ExtractMin();y = Q->ExtractMin();z->left = x;z->right = y;z->freq = x->freq + y->freq;Q->Insert(z);

} return Q->ExtractMin();}

Recommended