E130. Тернарный поиск

e-maxx algorithm original: C/C++ #algorithm #emaxx #math #numerical-methods #search
题目文本会按所选界面语言从俄语翻译;代码保持不变。

Источник: e-maxx.ru/algo, страница PDF 422.

Постановка задачи

Пусть дана функция

, унимодальная на некотором отрезке

. Под унимодальностью понимается один

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

it is required find максимум функции

на отрезке

.

算法

Возьмём любые две точки

и

в этом отрезке:

. Посчитаем значения функции

и

. Дальше у нас получается три варианта:

● Если окажется, что

, то искомый максимум не может находиться в левой части, т.е. в части . В этом легко убедиться: если в левой точке функция меньше, чем в правой, то либо эти две точки находятся в области "подъёма" функции, либо только левая точка находится там. В любом случае, это означает, что

максимум дальше имеет смысл искать только в отрезке

.

● Если, наоборот,

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

, поэтому переходим к отрезку

.

● Если

, то либо обе эти точки находятся в области максимума, либо левая точка находится в области возрастания, а правая — в области убывания (здесь существенно используется то, что возрастание/ убывание строгие). Таким образом, в дальнейшем поиск имеет смысл производить в отрезке

, но (в

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

поиска

находим новый отрезок

. Повторим теперь все действия для этого нового отрезка, снова

получим новый, строго меньший, отрезок, и т.д. Рано или поздно длина отрезка станет маленькой, меньшей заранее определённой константы-точности, и процесс можно останавливать. Этот метод численный, поэтому после остановки 算法а можно приближённо считать, что

во всех точках отрезка

достигается максимум; в качестве ответа можно взять, на示例, точку . Осталось заметить, что мы не накладывали никаких ограничений на выбор точек

и

. От этого способа,

понятно, будет зависеть скорость сходимости (но и возникающая погрешность). Наиболее распространённый способ

— выбирать точки так, чтобы отрезок

делился ими на 3 равные части:

Впрочем, при другом выборе, когда

и

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

Случай целочисленного аргумента

Если аргумент функции

整数, то отрезок

тоже становится дискретным, однако, поскольку мы

не накладывали никаких ограничений на выбор точек

и

, то на корректность 算法а это никак не влияет.

Можно по-прежнему выбирать

и

так, чтобы они делили отрезок

на 3 части, но уже равные

только приблизительно. Второй отличающийся момент — критерий остановки 算法а. В данном случае тернарный поиск надо

будет останавливать, когда станет

, ведь в таком случае уже невозможно будет выбрать точки

и

так, чтобы были различными и отличались от

и

, и это может привести к зацикливанию. После того, как

算法 тернарного поиска остановится и станет

, из оставшихся нескольких точек-

кандидатов

надо выбрать точку с максимальным значением функции.

实现

实现 для непрерывного случая (т.е. функция

имеет вид: ):

double l = ..., r = ..., EPS = ...; // 输入ные данные

while (r - l > EPS) {

double m1 = l + (r - l) / 3,

m2 = r - (r - l) / 3;

if (f (m1) < f (m2))

l = m1;

else

r = m2;

}

Здесь

— фактически, абсолютная погрешность ответа (не считая погрешностей, связанных с неточным вычислением функции). Вместо критерия "while (r - l > EPS)" можно выбрать и такой критерий останова:

for (int it=0; it<iterations; ++it)

С одной стороны, придётся подобрать константу

, чтобы обеспечить требуемую точность (обычно

достаточно нескольких сотен, чтобы достичь максимальной точности). Но зато, с другой стороны, number

итераций перестаёт зависеть от абсолютных величин

и

, т.е. мы фактически с помощью

задаём требуемую относительную погрешность.

C# 解法

自动草稿,提交前请检查
using System;
using System.Collections.Generic;
using System.Linq;

public static class AlgorithmDraft
{
    // Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
    double l = ..., r = ..., EPS = ...; // входные данные
    while (r - l > EPS) {
       double m1 = l + (r - l) / 3,
          m2 = r - (r - l) / 3;
       if (f (m1) < f (m2))
          l = m1;
       else
          r = m2;
    }
    for (int it=0; it<iterations; ++it)
}

C++ 解法

匹配/原始
double l = ..., r = ..., EPS = ...; // входные данные
while (r - l > EPS) {
   double m1 = l + (r - l) / 3,
      m2 = r - (r - l) / 3;
   if (f (m1) < f (m2))
      l = m1;
   else
      r = m2;
}
for (int it=0; it<iterations; ++it)

Java 解法

自动草稿,提交前请检查
import java.util.*;
import java.math.*;

public class AlgorithmDraft {
    // Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
    double l = ..., r = ..., EPS = ...; // входные данные
    while (r - l > EPS) {
       double m1 = l + (r - l) / 3,
          m2 = r - (r - l) / 3;
       if (f (m1) < f (m2))
          l = m1;
       else
          r = m2;
    }
    for (int it=0; it<iterations; ++it)
}

Материал разбит как 算法ическая 题目: изучить постановку, понять асимптотику и реализовать 算法 на выбранном языке.

Vacancies for this task

活跃职位 with overlapping task tags are 已显示.

所有职位
目前还没有活跃职位。