Задача о расстановке знаков в выражении — различия между версиями
Ruslan02 (обсуждение | вклад) (→Восстановление ответа) |
м (rollbackEdits.php mass rollback) |
||
(не показаны 3 промежуточные версии 2 участников) | |||
Строка 20: | Строка 20: | ||
'''int maxValueOfExpression'''(a, n): | '''int maxValueOfExpression'''(a, n): | ||
'''for''' i = 1 '''to''' n: | '''for''' i = 1 '''to''' n: | ||
− | d[i][i] = a[i] | + | d[i][i] = a[i] |
'''for''' i = n - 1 '''downto''' 1: | '''for''' i = n - 1 '''downto''' 1: | ||
Строка 148: | Строка 148: | ||
* <tex>d[i][j] = \max\limits_{\mathop{k = i..j-1}}[\max(d[i][k] + d[k + 1][j], p[i][k] \cdot p[k + 1][j])] \ (i < 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] \cdot p[k + 1][j])] \ (i < j)</tex> <br /> | ||
+ | == См. также == | ||
+ | *[[Задача о порядке перемножения матриц | Задача о порядке перемножения матриц]] | ||
+ | *[[Задача о наибольшей общей подпоследовательности | Задача о наибольшей общей подпоследовательности]] | ||
== Источники информации== | == Источники информации== |
Текущая версия на 19:07, 4 сентября 2022
Задача: |
Пусть задана последовательность неотрицательных чисел | . Требуется расставить знаки и скобки в последовательности, чтобы значение полученного арифметического выражения было максимальным.
Содержание
Решение
Данная задача решается с использованием принципа оптимальности на подотрезках. Введём матрицу размером , где будет равен максимальному значению, достигаемому на подотрезке .
Получаем следующие соотношения:
Вычислим элементы таблицы
, тогда ответом на задачу будет значение .Доказательство
Рассмотрим ее, например, в такой формулировке. В арифметическом выражении, операндами которого являются целые числа, а операциями — бинарные арифметические операции
и , расставить скобки так, чтобы результат оказался максимальным. Подзадачами, через которые мы будем выражать оптимальное решение, будут задачи об оптимальной расстановке скобок в произведениях наших операндов, начиная с -го и заканчивая -м. Запоминать результат оптимального решения соответствующей подзадачи мы будем в элементе матрицы, размером , диагональные элементы которой равны операндам, а для все элементы равны . Пусть мы хотим подсчитать значение арифметического выражения для операндов, начиная с -го и заканчивая -м для . Если мы предположим, что последней будет выполняться арифметическая операция, расположенная после операнда с номером и эта операция — сложение, то результат подсчета будет равен сумме элементов и нашей матрицы. С умножением ситуация несколько более сложная. Так как операндами могут быть и отрицательные числа, то для нахождения максимума из произведений нужно знать не только максимальные, но и минимальные значения для арифметических операций над операндами с -го по -й и с -го по -й соответственно. Значит для любой последовательности операндов нужно хранить значение как максимально, так и минимально возможного результата выполнения арифметических операций над ними. Однако, дополнительная матрица для хранения минимальных значений не нужна. Так как для матрица не заполнена, мы можем отвести эти элементы для хранения минимумов, только запоминать результат решения этой подзадачи для операндов, начиная с -го и заканчивая -м, мы будем в элементе . Тогда в общем случае, если после k-го операнда стоит операция умножения, то максимальный результат будет равен ;Реализация
// a - заданная последовательность из n элементов int maxValueOfExpression(a, n): 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])) return d[1][n]
Пример
Пусть дана последовательность
. Таблица для неё будет выглядеть так:Восстановление ответа
С помощью описанного выше алгоритма можно восстановить оптимальное арифметическое выражение. Для этого нужно в таблице
хранить каким способом был получен оптимальный ответ. То есть будем хранить — границу раздела на 2 подотрезка и и — операцию совершенную над двумя отрезками ( ). В итоге для каждого отрезка мы будем знать какой знак и куда поставить. Для простоты будем заключать каждый полученный подотрезок в скобки. Таким образом мы получим выражение, в котором полностью расставлены скобки.Для вышеприведенного примера таблица будет выглядеть так:
После того, как посчитана динамика, можно рекурсивно восстановить ответ:
- Если длина текущего отрезка равна , выходим из рекурсии
- Оборачиваем текущий отрезок в скобки
- Ставим после элемента последовательности на позиции знак
- Рекурсивно запускаем от отрезков и
Таким образом ответ
Решение задачи без возможности использования скобок
При условии задачи, в котором запрещено использовать скобки, вышеописанный алгоритм будет работать некорректно. Дело в том, что если на отрезке
См. также
Источники информации
- Олимпиадные задачи и решения — Классические задачи динамического программирования
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — с. 459. — ISBN 5-8489-0857-4