Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по алгоритмам.doc
Скачиваний:
6
Добавлен:
05.11.2018
Размер:
264.7 Кб
Скачать

Алгоритм 7. Динамического программирования для вычисления порядка, минимизирующего сложность умножения цепочки из n матриц m1m2…Mn

Вход. r0, r1, …, rn, где ri-1 и ri  числа строк и столбцов матрицы Mi.

Выход. Минимальная сложность умножения матриц Mi в предположении, что для умножения (pq)-матрицы на (qr)-матрицу требуется pqr операций.

Метод. Алгоритм заполняет последовательно «верхнетреугольную» матрицу минимальных сложностей умножения двух, трех, четырех, … и т.д. матриц из предлагаемой последовательности. На первом шаге заполняется строка, соответствующая сложности умножения двух матриц, взятых последовательно из предлагаемого произведения. На втором шаге рассчитываются минимальные сложности умножения трёх последовательных матриц, основываясь на известных минимальных сложностях умножения двух матриц. Заполняется соответствующая строка, и т.д.

Программа 7.

// Программа рассчитывает матрицу минимальных сложностей умножения NUM матриц,

// размеры которых r0, r1, …, rn заданы в массиве Sizes

#include <stdlib.h>

#include <stdio.h>

#include <io.h>

#define NUM 6 // Число перемножаемых матриц

#define NUM1 NUM+1 // Размер массива Sizes

unsigned Sizes[NUM1]; // Массив, содержащий размеры перемножаемых матриц

unsigned long Time_comp[(NUM1*NUM)>>1]; // Матрица минимальных сложностей умножения

Void main()

{

unsigned long value, temp, *ptr, *current[NUM<<1];

unsigned ind, index, count, curr, max, min;

// Здесь должна стоять функция ввода массива Sizes

// Процедура заполнения матрицы Time_copm с помощью метода

// динамического программирования

ptr=Time_comp;

for(index=0; index<NUM; *ptr++=0, index++); // Первая строка заполняется нулями

for (ind=1; ind<NUM; ind++)

{

max=(ind<<1)-1;

// Предварительный расчёт указателей на элементы матрицы Time_copm, которые

// используются в дальнейшем при выборе минимальной сложности умножения.

// Указатели хранятся в массиве current.

for(index=0; index<ind; index++)

{

count=(index*((NUM<<1)-index+1))>>1;

curr=count+ind-index;

current[index<<1]=&Time_comp[count];

current[(index<<1)+1]=&Time_comp[curr];

}

for (index=1; index<NUM; index++)

{

count=ind+index;

if(count>NUM) break;

// Выбор минимальной сложности умножения заданного количества матриц

value=4294967294; // максимальное число типа long int

for(curr=index; curr<count; curr++)

{

min=(curr-index)<<1;

temp=*current[min]++ + *current[max-min]++ + Sizes[index-1]*Sizes[curr]*Sizes[count];

if (value > temp) value=temp;

}

*ptr++=value; // Заполнение текущего элемента матрицы Time_comp

}

}

} // Конец main

Рассмотрим характерный пример умножения некоторого количества матриц.

Пример 1.8. Предположим, что требуется найти произведение шести матриц

M = M1M2M3 M4M5M6,

(157) (78) (846) (462) (239) (3938)

соответствующие размеры которых указаны под матрицами. Здесь величины r0, r1, r2, r3, r4, r5, r6 соответственно равны 15, 7, 8, 46, 2, 39, 38. В результате работы алгоритма 7 получается матрица минимальных сложностей умножения, показанная в таблице 4. Из матрицы видно, что минимальная сложность умножения данных шести матриц равна 5162. Из этой же таблицы несложно получить и порядок умножения матриц. Для этого надо приписать к каждой клетке таблицы то значение k, на котором достигается минимум (1.11). Для удобства полученные значения k показаны в маленьких левых нижних клетках, а в верхних маленьких клетках показаны индексы i и j из (1.11).

Таблица 4. Сложности вычисления произведений MiMi+1Mj

11

0

22

0

33

0

44

0

55

0

66

0

0

0

0

0

0

0

12

840

23

2576

34

736

45

3588

56

2964

1

2

3

4

5

13

6360

24

848

35

1360

46

6224

2

2

4

5

14

1058

25

1394

36

4308

1

4

4

15

2228

26

4344

4

4

16

5162

4

Теперь рассмотрим последнюю клетку таблицы

16

5162

4

Цифры в левом верхнем углу i=1, j=6 показывают, что данная клетка показывает минимальную сложность умножения матриц с первой по шестую. Эта сложность равна 5162. Цифра k=4 показывает оптимальную расстановку скобок, а именно  нужно умножить сначала матрицы (M1M2…M4), далее матрицы (M5M6), после чего найти произведение полученных сомножителей. Чтобы найти оптимальный способ умножения (M1M2…M4) необходимо найти в таблице ячейку с параметрами i=1, j=4. Число k=1 в этой ячейке указывает на то, что сначала необходимо найти произведение матриц (M2M3M4), а далее умножить его на M1. И так далее. В результате получается следующий способ оптимального умножения матриц с точки зрения сложности вычислений (и далеко не очевидный при самостоятельном поиске варианта расстановки скобок):

Mопт = (M1  (M2  (M3 M4)))  (M5M6).

(157) (78) (846) (462) (239) (3938)

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

M = M1M2M3 M4M5M6,

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