Изменения

Перейти к: навигация, поиск

Задача о порядке перемножения матриц

7 байт добавлено, 18:42, 3 января 2015
Нет описания правки
'''{{Задача о порядке перемножения матриц''' (англ. ''chain matrix multiplication'') — классическая задача, которая может быть решена с помощью динамического программирования. В этой задаче нам дается |definition = Дана последовательность из <tex>n</tex> матриц, в которой мы хотим найти самый эффективный способ их перемножения.}}
У нас есть множество способов перемножить матрицы, потому что операция перемножения ассоциативна. Другими словами, нет разницы в каком порядке расставляются скобки между множителями, результат будет один и тот же.
[[Правильные скобочные последовательности | Расстановок скобок]] достаточно много и их количество очень быстро растет. Точное количество всевозможных вариантов равно ''<tex>n''</tex>–ому [http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%9A%D0%B0%D1%82%D0%B0%D0%BB%D0%B0%D0%BD%D0%B0 числу Каталана].
Однако, порядок в котором расставляются скобки между матрицами повлияет на количество арифметических операций, которые потребуются на вычисление ответа, или, другими словами, на ''эффективность''.
Например, предположим, что А <tex>A = (10 &\times; 30)</tex>, <tex>B = (30 &\times; 5)</tex>, <tex>C = (5 &\times; 60)</tex>. Тогда:
:<tex>(''AB'')''C'' = (10&times;30&times;5\times30\times5) + (10&times;5&times;60\times5\times60) = 1500 + 3000 = 4500 </tex> операций:''<tex>A''(''BC'') = (30&times;5&times;60\times5\times60) + (10&times;30&times;60\times30\times60) = 9000 + 18000 = 27000 </tex> операций.
Как мы видим, первый способ гораздо эффективней.
Чтобы привести пример, давайте вернемся к нашим матрицам. Если у нас есть четыре матрицы ''<tex>ABCD''</tex>, то мы посчитаем для <tex>(''A'')(''BCD'')</tex>, <tex>(''AB'')(''CD'')</tex>, и <tex>(''ABC'')(''D'')</tex>, делая рекурсивные вызовы на отрезках ''<tex>ABC''</tex>, ''<tex>AB''</tex>, ''<tex>CD''</tex>, и ''<tex>BCD''</tex>, чтобы найти минимальную стоимость. Потом среди них выбираем лучший вариант. Так же, этот алгоритм дает не только минимальную стоимость, но и показывает наилучший способ перемножения матриц: нужно только сгрупировать тем же образом матрицы, каким дается нам минимальная стоимость.
Однако, если применить этот алгоритм, то обнаружим, что он работает также медленно, как и наивный способ перебирания всех скобочных последовательностей. Делается значительное количество ненужной работы. Например, в выше описанном алгоритме, осуществляется рекурсивный вызов, чтобы найти наилучшую стоимость для подсчета ''<tex>ABC'' </tex> и ''<tex>AB''</tex>. Но нахождение наилучшей стоимости для подсчета ''<tex>ABC'' </tex> так же требует нахождения лучшей стоимости для ''<tex>AB''</tex>. Так как рекурсия растет вглубь все больше и больше, то и число ненужных повторений увеличивается. Итоговая асимптотика, как было сказано выше, равняется ''<tex>n''</tex>–ому [http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%9A%D0%B0%D1%82%D0%B0%D0%BB%D0%B0%D0%BD%D0%B0 числу Каталана], да плюс вычисление для каждой правильной скобочной последовательности ''затрат'' на перемножение (то есть <tex>O(n \cdot C_n)</tex>). <!--Так как <tex>N</tex>­-ое число Каталана равняется <tex> \frac{1}{n+1}{2 n \choose n} </tex> или асимптотически <tex> \frac{4^n}{n^{3/2}\sqrt{\pi}} </tex>, что является быстро возрастающей функцией, нам бы хотелось решение, которое работает быстрее.-->
=== Оптимизации Оптимизация динамическим программированием ===Одно Одна из простых решений оптимизаций — это ''мемоизация'' (или ленивые вычисления)запоминание уже посчитанных значений. Каждый раз, когда считаем минимальную стоимость перемножения определенной подпоследовательности, давайте запоминать ответ. Если мы когда либо захотим посчитать это ещё раз, то уже будет иметь ответ и не будем пересчитывать. Поскольку существует всего <tex>O(n^2)</tex> подотрезков, где <tex>n</tex> — это количество матриц, то память занимаемая программой будет не так велика. С помощью запоминания ответа мы уменьшили асимптотику алгоритма (перебор) с <tex>O(n \cdot C_n)</tex> до <tex>O(n^3)</tex>, что является достаточно эффективным для реальных приложений.
=== Восстановление ответа ===
int matrixChainMultiplication(int l, int r)
{
//l — включая в отрезок //r — исключая из отрезка if dp[l][r] == -1 //Если значение динамики не посчитано if l == r - 1 dp[l][r] = 0; //Если у нас подотрезок длины 1, то количество операций для перемножения равно нулю else dp[l][r] = infinity; for (int i = l + 1; i < r; i++) dp[l][r] = min(dp[l][r], v[l] * v[i] * v[r - 1] + matrixChainMultiplication(l, i) + matrixChainMultiplication(i, r)); return dp[l][r];
}
</pre>
== Литература См. также ==*[[Правильные скобочные последовательности ]] == Источники информации ==
* Английская википедия [http://en.wikipedia.org/wiki/Matrix_chain_multiplication Matrix chain multiplication]*[http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%9A%D0%B0%D1%82%D0%B0%D0%BB%D0%B0%D0%BD%D0%B0 числа Каталана]
[[Категория: Дискретная математика и алгоритмы]]
[[Категория:Динамическое_программирование]]
251
правка

Навигация