Задача о расстановке знаков в выражении — различия между версиями
Ruslan02 (обсуждение | вклад) (→Источники) |
Ruslan02 (обсуждение | вклад) |
||
Строка 24: | Строка 24: | ||
'''for''' j = i + 1 '''to''' n: | '''for''' j = i + 1 '''to''' n: | ||
'''for''' k = i '''to''' j - 1: | '''for''' k = i '''to''' j - 1: | ||
− | d[i][j] = max(d[i][j], max(d[i][k] + d[k+1][j], d[i][k] * d[k + 1][j])); | + | d[i][j] = max(d[i][j], max(d[i][k] + d[k + 1][j], d[i][k] * d[k + 1][j])); |
'''print'''(d[1][n]); <font color="green">// вывод ответа</font> | '''print'''(d[1][n]); <font color="green">// вывод ответа</font> | ||
Строка 63: | Строка 63: | ||
| <tex>2</tex> | | <tex>2</tex> | ||
|} | |} | ||
+ | |||
+ | == Восстановление ответа == | ||
+ | С помощью описанного выше алгоритма можно восстановить оптимальное арифметическое выражение. Для этого нужно в таблице <tex>d</tex> хранить каким способом был получен оптимальный ответ. То есть будем хранить <tex>index</tex> {{---}} границу раздела на 2 подотрезка и <tex>operation</tex> {{---}} операцию совершенную над двумя отрезками (<tex>+, \times</tex>). В итоге для каждого отрезка мы будем знать какой знак и куда поставить. Для простоты будем заключать каждый полученный подотрезок в скобки. Таким образом мы получим выражение, в котором полностью расставлены скобки. | ||
+ | |||
+ | Для вышеприведенного примера ответ будет выглядеть так <tex> (2+1)\times(1+2)</tex> | ||
+ | |||
+ | == Решение задачи без возможности использования скобок == | ||
+ | При условии задачи, в котором запрещено использовать скобки, вышеописанный алгоритм будет работать некорректно. Дело в том, что если на отрезке <tex>k\dots j</tex> была использована операция сложения, то мы не можем перемножить результаты на отрезке <tex>i\dots k - 1</tex> и отрезке <tex>k\dots j</tex>. Для решения этой проблемы будем использовать две матрицы <tex>d</tex> {{---}} такую же как и раньше, а также <tex>p</tex> <tex>(p[i][j]</tex> {{---}} произведение чисел <tex dpi = "130">a_i, a_{i+1}, \dots, a_j)</tex>. Тогда получим новую формулу пересчета динамики: | ||
+ | <br /> | ||
+ | * <tex>d[i][j] = \max\limits_{\mathop{k = i..j-1}}[\max(d[i][k] + d[k + 1][j], p[i][k] \times p[k + 1][j])] \ (i < j)</tex> <br /> | ||
+ | |||
== Источники == | == Источники == |
Версия 22:39, 4 июня 2017
Задача: |
Пусть задана последовательность неотрицательных чисел | . Требуется расставить знаки и скобки в последовательности, чтобы значение полученного арифметического выражения было максимальным.
Содержание
Решение
Данная задача решается с использованием принципа оптимальности на подотрезках. Введём матрицу размером , где будет равен максимальному значению, достигаемому на подотрезке .
Получаем следующие соотношения:
Вычислим элементы таблицы
, тогда ответом на задачу будет значение .Доказательство
Рассмотрим ее, например, в такой формулировке. В арифметическом выражении, операндами которого являются целые числа, а операциями — бинарные арифметические операции
и , расставить скобки так, чтобы результат оказался максимальным. Подзадачами, через которые мы будем выражать оптимальное решение, будут задачи об оптимальной расстановке скобок в произведениях наших операндов, начиная с -го и заканчивая -м. Запоминать результат оптимального решения соответствующей подзадачи мы будем в элементе матрицы, размером , диагональные элементы которой равны операндам, а для все элементы равны . Пусть мы хотим подсчитать значение арифметического выражения для операндов, начиная с -го и заканчивая -м для . Если мы предположим, что последней будет выполняться арифметическая операция, расположенная после операнда с номером и эта операция — сложение, то результат подсчета будет равен сумме элементов и нашей матрицы. С умножением ситуация несколько более сложная. Так как операндами могут быть и отрицательные числа, то для нахождения максимума из произведений нужно знать не только максимальные, но и минимальные значения для арифметических операций над операндами с -го по -й и с -го по -й соответственно. Значит для любой последовательности операндов нужно хранить значение как максимально, так и минимально возможного результата выполнения арифметических операций над ними. Однако, дополнительная матрица для хранения минимальных значений не нужна. Так как для матрица не заполнена, мы можем отвести эти элементы для хранения минимумов, только запоминать результат решения этой подзадачи для операндов, начиная с -го и заканчивая -м, мы будем в элементе . Тогда в общем случае, если после k-го операнда стоит операция умножения, то максимальный результат будет равен ;Реализация
// d - матрица как в описании; a - последовательность из n элементов; i, j, k - счётчики for i = 1 to n: d[i][i] = a[i]; for i = n - 1 downto 1: for j = i + 1 to n: for k = i to j - 1: d[i][j] = max(d[i][j], max(d[i][k] + d[k + 1][j], d[i][k] * d[k + 1][j])); print(d[1][n]); // вывод ответа
Пример
Пусть дана последовательность
. Таблица для неё будет выглядеть так:Восстановление ответа
С помощью описанного выше алгоритма можно восстановить оптимальное арифметическое выражение. Для этого нужно в таблице
хранить каким способом был получен оптимальный ответ. То есть будем хранить — границу раздела на 2 подотрезка и — операцию совершенную над двумя отрезками ( ). В итоге для каждого отрезка мы будем знать какой знак и куда поставить. Для простоты будем заключать каждый полученный подотрезок в скобки. Таким образом мы получим выражение, в котором полностью расставлены скобки.Для вышеприведенного примера ответ будет выглядеть так
Решение задачи без возможности использования скобок
При условии задачи, в котором запрещено использовать скобки, вышеописанный алгоритм будет работать некорректно. Дело в том, что если на отрезке
Источники
Список литературы
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — с. 459. — ISBN 5-8489-0857-4