Индуктивные функции на пространстве последовательностей
Применение теории индуктивных функций
В качестве первого примера рассмотрим уже встречавшуюся нам ранее задачу.
Задача 9.1. Напишите программу, вводящую последовательность целых чисел, и печатающую количество ее максимальных элементов.
Решение В данной задаче , , . Взяв , , , находим , но . Из отрицания критерия индуктивности заключаем, что не является индуктивной.
Для построения ее индуктивного расширения применим стандартный прием. Попробуем выразить значение функции на удлиненной цепочке через ее значение на исходной и элемент . Известно, что это невозможно сделать ( — не является индуктивной), но наша цель — понять какой именно информации не хватает и, добавив ее, образовать функцию . Рассмотрим теперь функцию . В том случае, если она индуктивна, требуемое расширение построено. Иначе повторим предыдущие действия и попытаемся выразить и через , и с использованием дополнительной информации . Получаем следующего кандидата на роль индуктивного расширения — функцию . При необходимости данный процесс может быть продолжен и далее, а его завершение гарантируется теоремой о существовании индуктивного расширения. В данном случае имеем ,
Мы видим, что в качестве следует взять функцию , вычисляющую максимальное значение элементов цепочки. Тогда для получаем
Эта функция, однако, не определена на пустой цепочке, поэтому также определена только на . Воспользовавшись тем, что диапазон представления целых чисел на ЭВМ ограничен, в данном случае можно доопределить с сохранением функции перевычисления следующим образом: "Integer.MIN\_VALUE" ( для языка Java). Действительно, если принять, что максимальным элементом пустой цепочки является минимально представимое на ЭВМ целое число, то , а функция определяется формулой
Докажем, что построенное нами расширение не является минимальным. Для этого достаточно предъявить значение , которое не принимается ни на одной цепочке. Таковым будет, например, . Докажите самостоятельно, что если вместо пространства рассмотреть , то построенное нами расширение окажется минимальным.
Теперь можно написать программу, реализующую построенный алгоритм.
Текст программы
public class NumMaxSeq2 { public static void main(String[] args) { int y1 = 0, y2 = Integer.MIN_VALUE; try { while (true) { int x = Xterm.inputInt("x -> "); if (x == y2) { y1 += 1; } else if(x > y2) { y1 = 1; y2 = x; } } } catch (Exception e) { Xterm.println("\nn = " + y1); } } }
Любая ошибка при вводе рассматривается здесь, как завершение последовательности чисел. Имена переменных, имеющихся в программе, совпадают с использованными при построении алгоритма, вычисление выполняется с помощью команд "int y1=0, y2=Integer.MIN\_VALUE;", функция реализована при помощи оператора if-else, в котором опущен случай (так как тогда не нужно изменять ни , ни ), а применение отображения сводится к печати только значения из вычисленных и .
Следующая задача нам тоже уже знакома.
Задача 9.2. Напишите программу, определяющую номер первого элемента, равного , в последовательности целых чисел. В том случае, если число в последовательности не встречается, положите равным нулю.
Решение Имеем , где , а . Если , , , то , но , следовательно не является индуктивной.
Построим ее индуктивное расширение . Заметим, что ,
Следовательно, в качестве можно взять пару , где функция . Эта функция уже индуктивна, так как , а преобразование имеет вид
Заметим, что все значения функции , отличные от нуля, являются стационарными, в то время как функция не имеет стационарных значений. Ясно, что отображение имеет вид .
Построенное нами расширение не является минимальным, так как значение не может быть принято функцией ни на одной цепочке.
Вот программа, не использующая наличия стационарных значений.
Текст программы
public class First1{ public static void main(String[] args) throws Exception { int x0 = Xterm.inputInt("x0 ->"); int y1 = 0, y2 = 0; try { while (true) { int x = Xterm.inputInt("x -> "); y2 += 1; if ( (y1 == 0) && (x == x0) ) y1 = y2; } } catch (Exception e) { Xterm.println("\nn = " + y1); } } }
Имена программных переменных совпадают с использованными при построении алгоритма, вычисление выполняется с помощью команд "int y1=0, y2=0;", реализация функции очевидна, а применение отображения сводится к печати только значения .
Программа, использующая наличие у функции стационарных значений, может выдавать ответ сразу же, как только одно из таких значений будет достигнуто.
Текст программы
public class First2 { public static void main(String[] args) throws Exception { int x0 = Xterm.inputInt("x0 -> "); int y1 = 0, y2 = 0; try { while (y1 == 0) { int x = Xterm.inputInt("x -> "); y2 += 1; if (x == x0) y1 = y2; } } catch(Exception e){ System.exit(0); } Xterm.println("\nn = " + y1); } }
По достижению конца вводимой последовательности эта программа не выполняет никаких специальных действий (оператор ";" в блоке "catch" ). В этой ситуации, как и в случае принятия функцией любого из стационарных значений ( ), управление просто передается на оператор печати.