Индуктивные функции на пространстве последовательностей
Применение теории индуктивных функций
В качестве первого примера рассмотрим уже встречавшуюся нам ранее задачу.
Задача 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" ).
В этой ситуации, как и в случае принятия функцией любого из
стационарных
значений (
), управление просто передается на оператор
печати.