Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Полное построение алгоритма шаг за шагом
Построение модели Задача четко поставлена, теперь нужно сформулировать для нее математическую модель. Это очень важный шаг в процессе решения, и его надо хорошо обдумать. Выбор модели существенно влияет па остальные этапы в процессе решения. Как вы можете догадаться, невозможно предложить набор правил, автоматизирующих стадию моделирования. Большинство задач должно рассматриваться индивидуально. Тем не менее существует несколько полезных руководящих принципов. Выбор модели — в большей степени дело искусства, чем науки, и, вероятно, эта тенденция сохранится. Изучение удачных моделей — это наилучший способ приобрести опыт в моделировании. Приступая к разработке модели, следует задать по крайней мере два основных вопроса: 1. Какие математические структуры больше всего подходят для задачи? 2. Существуют ли решенные аналогичные задачи? Второй вопрос, возможно, самый полезный во всей математике. В контексте моделирования он часто дает ответ на первый вопрос. Действительно, большинство решаемых в математике задач, как правило, являются модификациями ранее решенных. Большинство из нас просто не обладает талантом Ньютона, Гаусса или Эйнштейна, и для продвижения вперед нам приходится руководствоваться накопленным опытом. Сначала нужно рассмотреть первый вопрос. Мы должны описать математически, что мы знаем и что хотим найти. На выбор соответствующей структуры будут оказывать влияние такие факторы, как: 1) ограниченность наших знаний относительно небольшим количеством структур, 2) удобство представления, 3) простота вычислений, 4) полезность различных операций, связанных с рассматриваемой структурой или структурами. Сделав пробный выбор математической структуры, задачу следует переформулировать в терминах соответствующих математических объектов. Это будет одна из возможных моделей, если мы можем утвердительно ответить на такие вопросы, как: Вся ли важная информация задачи хорошо описана математическими объектами? Существует ли математическая величина, ассоциируемая с искомым результатом? Выявили мы какие-нибудь полезные отношения между объектами модели? Можем мы работать с моделью? Удобно ли с ней работать? Пример. Возвращаемся к задаче агента по продаже компьютеров, рассмотренной ранее в этом разделе. Начинаем с постановки задачи, данной в конце примера.
Решали ли мы ранее аналогичные задачи? В математическом смысле, вероятно, нет. Однако все мы сталкивались с задачами выбора пути по дорожным картам или в лабиринтах. Можем ли мы прийти к удобному представлению нашей задачи наподобие карты? Очевидно, нужно взять лист бумаги и нанести на нем по одной точке, соответствующей каждому городу. Мы не собираемся изображать точки так, чтобы расстояние между каждой парой точек, соответствующих городам.i и /, было пропорционально стоимости проезда Cij. Расположим точки любым удобным способом, соединим точки i и / линиями и проставим на них «веса» Сц. Схема, которую мы только что изобразили,— это частный случай известного в математике графа, или сети. В общем случае сеть — это множество точек (на плоскости) вместе с линиями, соединяющими некоторые или все пары точек; над линиями могут быть проставлены веса. Для простоты предположим, что у Джека только пять городов, для которых матрица стоимостей показана на рис. 1.3.1, а. Тогда сетевая модель может быть изображена, как на рис. 1.3.1, б. Предположим также, что стоимость проезда из города i в город / такая же, как н из / в I, хотя это и необязательно. Что мы ищем в задаче? В терминах теории сетей список городов (который мы ранее описали) определяет замкнутый цикл, начинающийся с базового города и возвращающийся туда же после прохождения каждого города по одному разу. Такой цикл соответствует неотрывному движению карандаша вдоль линий сети, которое проходит через каждую точку только один раз и начинается и оканчивается в одной и той же точке. Обход такого
рода назовем туром. Стоимость тура определяется как сумма весов всех пройденных ребер. Задача решена, если мы можем найти тур с наименьшей стоимостью. На рис. 1.3.1,6 обход 1—5—3—4—2—1 есть тур со стоимостью 5+2+1+4+1 = 13. Является ли он туром с минимальной стоимостью? Рассмотренная задача известна в литературе как задача коммивояжера; она стала в какой-то мере классической. Это один из наиболее известных примеров таких задач, которые очень легко поставить и промоделировать, но очень трудно решить. Время от времени мы будем возвращаться к этой задаче в целях иллюстрации.
Разработка алгоритма Как только задача четко поставлена и для нее построена модель, мы должны приступить к разработке алгоритма ее решения. Выбор метода разработки, зачастую сильно зависящий от выбора модели, может в значительной степени повлиять на эффективность алгоритма решения. Два разных алгоритма могут быть правильными, но очень сильно отличаться по эффективности. В одном из следующих разделов этой главы обсуждаются критерии эффективности. Пример. Вернемся к коммивояжеру из предыдущего раздела. Постановка задачи и модель, описанные ранее, наводят на мысль о следующем алгоритме. Сначала произвольно перенумеруем n городов целыми числами от 1 до п, присваивая каждому городу свой номер. Базовому городу приписываем номер п. Заметим, что каждый тур однозначно соответствует перестановке целых чисел 1,2,..., n—1. Действительно, каждый тур соответствует единственной перестановке, и каждая перестановка соответствует единственному туру. Такое соответствие называется взаимно-однозначным. Таким образом, для любой данной перестановки мы можем легко проследить соответствующий тур на сетевой модели и в то же время вычислить стоимость этого тура. Можно решить задачу, образуя все перестановки первых n—1 целых положительных чисел. Для каждой перестановки строим соответствующий тур и вычисляем его стоимость. Обрабатывая таким образом все перестановки, запоминаем тур, который к текущему моменту имеет наименьшую стоимость. Если мы находим тур с более низкой стоимостью, то производим дальнейшие сравнения с этим туром. Algorithm ETS (Исчерпывающий коммивояжер). Решить задачу коммивояжера с N городами, последовательно рассматривая все перестановки из N—1 положительных целых чисел. Таким образом мы рассмотрим каждый возможный тур и выберем вариант TOUR с наименьшей стоимостью MIN. Алгоритм ETS требует в качестве входных данных число городов N и матрицу стоимостей С. Шаг 0. [Инициализация, т. е. установка в начальное состояние] Set TOUR^-0; and MIN^-oo. Шаг 1. [Образование всех перестановок] For /-<-1 to (N—1)! do through шаг 4 od; and STOP. Шаг 2. [Получение новой перестановки] Set P-+-I-я перестановка целых чисел 1,2,..., N—1. (Заметим, что здесь нужен под алгоритм.) Шаг 3. [Построение нового тура] Строим тур Т(Р), соответствующий перестановке Р; and вычисляем стоимость COST (Т (Р)). (Заметим, что здесь нужны два других под алгоритма.) Шаг 4. [Сравнение] If COST (7,(P))<MIN then set TOUR+- <-T(P); and MIN^COST (7(P)) fi. Алгоритм ETS — неплохое первое приближение к точному алгоритму. Ему недостает некоторых важных под алгоритмов, и он недостаточно близок к окончательной программе. Эти недостатки будут устранены позже. Похоже, что существует тенденция: программисты затрачивают относительно небольшое время на стадию разработки алгоритма при создании программы. Проявляется сильное желание как можно быстрее начать писать самое программу. Этому побуждению не надо поддаваться. На стадии разработки требуется тщательное обдумывание, следует также уделить внимание двум предшествующим и первым трем следующим за стадией разработки этапам. Как и следует ожидать, все восемь основных этапов, перечисленных в разд. 1.1, нельзя рассматривать независимо друг от друга. В особенности первые три сильно влияют на последующие, а шестой и седьмой этапы обеспечивают ценную обратную связь, которая может заставить нас пересмотреть некоторые из предшествующих этапов.
3.Правильность алгоритма Доказательство правильности алгоритма — это один из наиболее трудных, а иногда и особенно утомительных этапов создания алгоритма. Вероятно, наиболее распространенная процедура доказательства правильности программы — это прогон ее на разных тестах. Если выданные программой ответы могут быть подтверждены известными или вычисленными вручную данными, возникает искушение сделать вывод, что программа «работает». Однако этот метод редко исключает все сомнения; может существовать случай, в котором программа не сработает. Мы предложим следующую общую методику доказательства правильности алгоритма. Предположим, что алгоритм описан в виде последовательности шагов, скажем, от шага 0 до шага т. Постараемся предложить некое обоснование правомерности для каждого шага. В частности, может потребоваться лемма об условиях, действующих до и после пройденного шага. Затем постараемся предложить доказательство конечности алгоритма, при этом будут проверены все подходящие входные данные и получены все подходящие выходные данные. Пример. Алгоритм ETS настолько прост, что его правильность легко доказать. Поскольку проверяется каждый тур, должен быть проверен и тур с минимальной стоимостью; как только до него дойдет очередь, он будет запомнен. Он не будет отброшен — это может случиться только в том случае, если существует тур с меньшей стоимостью. Алгоритм должен закончить работу, так как число туров, которые нужно проверить, конечно. Подобный метод доказательства известен как «доказательство исчерпыванием»; это самый грубый из всех методов доказательства. Подчеркнем тот факт, что правильность алгоритма еще ничего не говорит о его эффективности. Исчерпывающие алгоритмы редко бывают хорошими во всех отношениях. 4.Реализация алгоритма Как только алгоритм выражен, допустим, в виде последовательности шагов и мы убедились в его правильности, настает черед реализации алгоритма, т. е. написания программы для ЭВМ. Этот существенный шаг может быть довольно трудным. Во-первых, трудность заключается в том, что очень часто отдельно взятый шаг алгоритма может быть выражен в форме, которую трудно перевести непосредственно в конструкции языка программирования. Например, один из шагов алгоритма может быть записан в виде, требующем целой подпрограммы для его реализации. Во-вторых, реализация может оказаться трудным процессом потому, что перед тем, как мы сможем начать писать программу, мы должны построить целую систему структур данных для представления важных аспектов используемой модели. Чтобы сделать это, необходимо ответить, например, на такие вопросы:
Каковы основные переменные? Каких они типов? Сколько нужно массивов и какой размерности? Имеет ли смысл пользоваться связными списками? Какие нужны подпрограммы (возможно, уже записанные в памяти)? Каким языком программирования пользоваться? Конкретная реализация может существенно влиять на требования к памяти и на скорость алгоритма. Другой аспект построения программной реализации —• это программирование сверху - вниз. Объяснение этого понятия будет дано в разд. 2.1, а пока укажем, что программирование сверху - вниз — это подход к разработке и реализации, который состоит в преобразовании алгоритма в такую последовательность все более конкретизированных алгоритмов, что окончательный вариант представляет собой программу для ЭВМ. Сделаем одно важное замечание. Одно дело — доказать правильность конкретного алгоритма, описанного в словесной форме. Другое дело — доказать, что данная машинная программа, предположительно являющаяся реализацией этого алгоритма, также правильна. Таким образом, необходимо очень тщательно следить, чтобы процесс преобразования правильного алгоритма (в словесной форме) в машинную программу «заслуживал доверия». Советуем читателю снова рассмотреть алгоритм ETS в свете обсуждения в данном подразделе и постараться построить его по этапам, как было предложено, пока вы не получите машинную программу.
5.Анализ алгоритма и его сложности Существует ряд важных практических причин для анализа алгоритмов. Одной из них является необходимость получения оценок или границ для объема памяти или времени работы, которое потребуется алгоритму для успешной обработки конкретных данных. Машинное время и память — относительно дефицитные (и дорогие) ресурсы, на которые часто одновременно претендуют многие пользователи. Всегда следует избегать прогонов программы, отвергаемых системой из-за нехватки запрошенного времени, которое указывается на рабочей карте. Поразительно, скольким программистам приходится слишком дорогим способом выяснять, что их программа не может обработать входные данные раньше, чем через несколько дней машинного времени. Лучше было бы предугадать такие случаи с помощью карандаша и бумаги для того, чтобы избежать ненужных прогонов. Хороший анализ способен выявить узкие места в наших программах, т. е. разделы программы, на которые расходуется большая часть времени (см. упр. 1.3.16).
Существуют также важные теоретические причины для анализа алгоритмов. Хотелось бы иметь некий количественный критерий для сравнения двух алгоритмов, претендующих на решение одной и той же задачи. Более слабый алгоритм должен быть улучшен или отброшен. Желательно также иметь механизм для выявления наиболее эффективных алгоритмов и замены устаревших. Иногда невозможно составить четкое мнение об относительной эффективности двух алгоритмов. Один может в среднем лучше работать, к примеру, на случайных входных данных, в то время как другой лучше работает на каких-то специальных входных данных. Хотелось бы иметь возможность делать аналогичные выводы о сравнительных достоинствах двух алгоритмов. Важно также установить абсолютный критерий. Когда можно считать решение задачи оптимальным? Иными словами, когда наш алгоритм настолько хорош, что невозможно (независимо от наших умственных способностей) значительно его улучшить? Пусть А — алгоритм для решения некоторого класса задач, an — размерность отдельной задачи из этого класса. Во многих задачах в этой книге n — просто скаляр, равный числу вершин графа. В общем случае n может быть массивом или длиной вводимой последовательности. Определим fA (п) как рабочую функцию, дающую верхнюю границу для максимального числа основных операций (сложения, сравнения и т. д.), которые должен выполнить алгоритм А для решения любой задачи размерности п. Будем пользоваться следующим критерием для оценки качества алгоритма А. Говорят, что алгоритм А полиномиальный, если fA(n) растет не быстрее, чем полином от п, в противном случае алгоритм А экспоненциальный. Этот критерий основан на времени работы в худшем случае, но аналогичный критерий может быть также определен для среднего времени работы. «периментальная» основа для этого критерия качества заключается в том, что, по-видимому, последовательные или параллельные машины более или менее способны воспринимать полиномиальные алгоритмы для больших задач, а на экспоненциальных алгоритмах они довольно быстро «задыхаются». Следующее обозначение стандартно во многих математических дисциплинах, в том числе и в анализе алгоритмов. Функцию }(n) определяют как О и говорят, что она порядка g(n) для больших п, если lim = constant =/=0. П оо § (я) ^ Это обозначается, как f(n)=0[g(n)]. Функция h(n) является о [z(n) для больших я, если lim = П-+ ОО 2 (я) Эти символы произносятся соответственно, как «О большое» и «о малое». Интуитивно, если /(z) есть 0[g(n)], то эти две функции, по существу, возрастают с одинаковой скоростью при z-*-оо. Если /(z) есть o[g(n)], то g(n) возрастает гораздо быстрее, чем (z). 7.Примеры алгоритмов Генетический алгоритм Генетический алгоритм (англ. genetic algorithm) — это эвристический алгоритм поиска, используемый для решения задач оптимизации и моделирования путём последовательного подбора, комбинирования и вариации искомых параметров с использованием механизмов, напоминающих биологическую эволюцию. Является разновидностью эволюционных вычислений (англ. evolutionary computation). Отличительной особенностью генетического алгоритма является акцент на использование оператора «скрещивания», который производит операцию рекомбинации решений-кандидатов, роль которой аналогична роли скрещивания в живой природе. Пример #include <stdio.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <vector> using namespace std; #define KEY_LEN 2048 // Длина ключа bool key[KEY_LEN]; //Неизвестный ключ #define POP_SIZE 20 // Размер популяции #define ELITE 5 // Количество привелигированных особей struct gen_struct { // Особь, кортеж из генов и значения пригодности bool gen[KEY_LEN]; int fitness; gen_struct(){ //Инициализация случайными значениями for(int i=0;i<KEY_LEN;++i) gen[i]=(random()%2==0); } bool operator<(const gen_struct & g)const{ return (g.fitness>fitness); } gen_struct(const gen_struct& g){ for(int i=0;i<KEY_LEN;++i) gen[i]=g.gen[i]; fitness=g.fitness; } void Mutate(){ //Оператор мутаций gen[random()%KEY_LEN]=random()%2; } void Crossingover(gen_struct & g){ //Оператор скрещивания for(int i=0;i<KEY_LEN;++i){ if(random()%2){ gen[i]=g.gen[i]; } } } }; int Fitness(bool gen[]){ //Целевая функция int ret=0; for(int i=0;i<KEY_LEN;i++){ ret+=(key[i]!=gen[i]); } return ret; } void GA(gen_struct &ret){ vector<gen_struct> pop; pop.resize(POP_SIZE); while(1){ for(int i=0;i<POP_SIZE;++i) if((pop[i].fitness=Fitness(pop[i].gen))==0){ ret=pop[i]; return; } sort(pop.begin(), pop.end()); for(int i=ELITE;i<POP_SIZE;++i){// 5 лучших остаются без изменений pop[i].Crossingover(pop[random()%(ELITE)]); pop[i].Mutate(); } } } int main(){ for(int i=0;i<KEY_LEN;i++){ key[i]=(random()%2==0); } gen_struct ret; GA(ret); cout << "key="; for(int i=0;i<KEY_LEN; i++){ cout << ret.gen[i]; } cout << endl; } Преимущества ГА Большое число свободных параметров, позволяющим эффективно встраивать эвристики; Эффективное распараллеливание; Работает заведомо не хуже абсолютно случайного поиска; Связь с биологией, дающая некоторую надежду на исключительную эффективность ГА в природе. Недостатки ГА Большое количество свободных параметров, которое превращает "работу с ГА" в "игру с ГА"; Недоказанность сходимости; В простых целевых функциях (гладкие, один экстремум и т.п.) генетика всегда проигрывает по скорости простым алгоритмам поиска. Волново́й алгори́тм — алгоритм, позволяющий найти минимальный путь в графе с рёбрами единичной длины. Основан на алгоритме поиска в ширину. Применяется для нахождения кратчайшего пути в графе, в общем случае находит лишь его длину. Содержание: Суть алгоритма На двумерной клетчатой карте (матрице), состоящей из «проходимых» и «непроходимых» клеток, обозначена клетка старта и клетка финиша. Цель алгоритма — проложить кратчайший путь от клетки старта к клетке финиша, если это, конечно, возможно. От старта во все направления распространяется волна, причем каждая пройденная волной клетка помечается как «пройденная». Волна, в свою очередь, не может проходить через клетки, помеченные как «пройденные» или «непроходимые». Волна движется, пока не достигнет точки финиша или пока не останется не пройденных клеток. Если волна прошла все доступные клетки, но так и не достигла клетки финиша, значит, путь от старта до финиша проложить невозможно. После достижения волной финиша, от финиша прокладывается путь до старта и сохраняется в массиве. Разновидности Практическое применение Волновой алгоритм — один из основных при автоматизированной трассировке (разводке) печатных плат. Также одно из характерных применений волнового алгоритма — поиск кратчайшего расстояния на карте в стратегических играх. Численные алгоритмы Методы интерполяции Алгоритм Герона Векторный алгоритм Описание Его можно представить как: «расскажи своим соседям, как выглядит Кэп». Каждый узел ведет таблицу маршрутизации с одной записью для каждого маршрутизатора подсети. Таблица представляет собой вектор, содержащий 2 компонента: выбранную линию и дистанцию. Узел оценивает дистанцию (количество ходов, задержку или длину очереди) до каждого соседа и рассылает её своим соседям, которые в свою очередь выполняют то же самое. В результате полученной информации каждый узел заново подсчитывает таблицу маршрутизации. Применяется в протоколе маршрутизации RIP. Впервые был применен в ARPANET. Алгоритм Предположим, что таблица только что была получена от соседа X, причем Xi является предположением X о том, сколько длится путь до маршрутизатора i. Если маршрутизатор знает, что передача данных до X длится m, то он знает так же, что он может достичь любой маршрутизатор і через X за Xi+m. Плюсы и минусы +самоорганизация +относительно простая реализация -плохая конвергенция («сходимость») -сложности при расширении сети Пример Алгоритмы баз данных При запуске программы пользователю будет предоставлена возможность выбора одного из восьми действий с списками (добавить, удалить из журнала посетителей, удалить из картотеки, редактировать, просмотреть, найти, редактировать, выйти из программы). Это меню будет высвечиваться каждый раз после выполнения действия, т.е. если пользователь выберет пункт «добавить» и введет данные пациента перед ним снова высветятся те же пункты меню и он сможет снова выбрать желаемое действие. Этот процесс будет выполнятся до тех пор, пока пользователь не выберет пункт главного меню «Выход». Алгоритм работы программы зависит от выбора пользователя. Рассмотрим каждый вариант ответа пользователя и реакцию программы: При выборе пользователем пункта 1, пользователь добавляет информацию о пациенте. При этом пользователь изначально вводит данные в таблицу посещений. После нажатия подтверждения выбора, экран перед пользователем очистится, и высветится приглашение ввести данные о пациенте (см. рис. 4.1).
Рисунок 4.1 – Алгоритм добавления новых данных
Если в главном меню выбран пункт 2, т.е. пользователь высказал свое желание удалить запись из журнала посещаемости. После осуществления выбора на экране высвечивается полный, нумерованный список посещений. Для продолжения пользователь выбирает номер записи, которую необходимо удалить (см. рис. 4.2.).
Рисунок 4.2 – Алгоритм удаления записи из журнала посещений
При выборе пункта 3, удаление из картотеки, выполняется более сложный алгоритм удаления. Удаляя запись о пациенте из картотеки пользователь автоматически удаляет все записи о нем и из журнала посещений. При выборе данного пункта перед пользователем высветятся данные картотеки, тоже пронумерованные, и пользователю необходимо только выбрать номер удаляемого пациента (см. рис. 4.3).
Рисунок 4.3 – Алгоритм удаления данных из картотеки При выборе 4-ого пункта происходит редактирование данных. При этом перед пользователем будет поставлен выбор – редактирование информации из первой либо из второй таблицы он желает осуществить (из журнала посетителей или из картотеки). В зависимости от выбора пользователя перед ним высветятся либо данные картотеки либо данные журнала посетителей и пользователь выберет номер редактируемой записи..При этом все данные выбранной строки удаляются и пользователь заново введет все данные о пациенте в выбранную таблицу (см. рис. 4.4).
Рисунок 4.4 – Алгоритм редактирования данных
При выборе пункта просмотра пользователю будут предложены два варианта – просмотр списка посещений либо просмотр картотеки. Выбранная таблица высветится на экране (см. рис. 4.5).
Рисунок 4.5 – Алгоритм просмотра данных
При выборе пользователем пункта меню поиска по фамилии пользователю необходимо ввести фамилию искомого пациента. При этом на экране высветятся сначала данные из картотеки, а потом – все записи из Журнала посещений, содержащие его фамилию (см. рис. 4.6).
Рисунок 4.6 – Алгоритм поиска по фамилии Выход. При выборе этого пункта пользователем будет осуществлен выход из программы (см. рис. 4.8).
Рисунок 4.8 – алгоритм выхода из программы Полное построение алгоритма шаг за шагом
1.Постановка задачи. 2.Построение модели. 3.Проверка правильности алгоритма. 4.Реализация алгоритма. 5.Анализ алгоритма и его сложности. 6.Примеры алгоритмов
Алгоритмы Каждый, кто решал задачи с помощью ЭВМ, имеет интуитивное представление о значении слова алгоритм есть кто даже утверждает, что это одно из важнейших понятий вычислительной математики. Попытаемся сначала выразить наши интуитивные соображения. Мы можем нестрого определить алгоритм как однозначно трактуемую процедуру решения задачи. Процедура — это конечная последовательность точно определенных шагов или операций, для выполнения каждой из которых требуется конечный объем оперативной памяти и конечное время. Дополнительно потребуем, чтобы алгоритм работал конечное время для любых входных данных. Одно из неудобств этого определения состоит в том, что термин «однозначная трактовка» весьма неоднозначен. «Однозначен» для кого? Или по отношению к чему? Поскольку ничто не является абсолютно ясным или абсолютно неясным, должен быть указан, хотя бы неявно, исполнитель. Алгоритм вычисления производной кубического полинома может быть вполне ясен тем, кто знаком с анализом, но для прочих он может оказаться совершенно непонятным. Таким образом, следует также указать вычислительные возможности исполнителя. Существуют и другие трудности с определением. Может случиться, что алгоритм заведомо существует для конкретной задачи, но его трудно или невозможно описать в некоторой заданной форме. Человечество разработало эффективный алгоритм завязывания шнурков на ботинках. Многие дети с пятилетнего возраста могут зашнуровывать свои ботинки. Но дать чисто словесное описание такого алгоритма без картинок и демонстрации — очень трудно. Очевидно, что в нашем определении есть некоторые недостатки. Можно избежать большинства этих недостатков, определив «математические машины» с очень точно указанными возможностями. Тогда мы скажем, что алгоритм — это некоторая процедура, которая может выполняться такой машиной. Подобные попытки определения алгоритма очень глубоки и трудны математически, и они слишком негибки для наших целей. Нам хотелось бы сохранить некоторую гибкость и интуитивную привлекательность первого определения и в то же время, хотя бы частично, устранить некоторые из его неопределенностей. Это легко сделать, описав «типичный» современный компьютер и язык общения с ним и определив затем алгоритм как процедуру, которая может быть реализована на этом компьютере при помощи данного языка. Этот компьютер будет иметь неограниченную память с произвольным доступом, в которой могут храниться действительные и целые числа, а также логические константы. В одном слове этой памяти можно хранить произвольное конечное число, и можно извлечь любое слово за фиксированное, постоянное время (это удобное предположение, может быть, немного нереалистично, но на практике это почти так). Такой компьютер может выполнять хранимую программу, которая состоит из допустимой последовательности команд, охватывающих все стандартные арифметические операции, операции сравнения, переходы и т. д. Обычно мы будем считать, что каждая такая команда выполняется за единицу времени. Простыми описаниями часть памяти может быть организована в одно-, двух- и трехмерные массивы (матрицы). Мы будем пользоваться языком Фортран в качестве модели возможностей нашей машины, когда нужно будет что-то конкретизировать. По сути дела мы утверждаем, что только тогда имеется алгоритм для решения задачи, когда можно написать программу для ЭВМ, решающую эту задачу. Это спорный вопрос. Программы на описанном выше компьютере не могут зашнуровывать ботинки. Среди точно определенных шагов не содержатся шаги, необходимые для завязывания шнурков. Имеются весомые аргументы в пользу того, что мы на самом деле оперируем ограниченным понятием алгоритма. Человек, как машина, способен выполнять множество тонких операций, которые лежат за рамками возможностей нашего типичного компьютера. Однако ограниченное определение — это как раз то, что нам требуется в данной книге. Следующий пример алгоритма иллюстрирует уровень детализации, согласующийся с нашим определением. В приложении А содержится подробное обсуждение правил и условных обозначений, использованных в книге для описания алгоритмов. Рассмотрим простую задачу нахождения максимального числа в списке из N действительных чисел R(1), R(2),..., R(N). Основная идея алгоритма заключается в том, чтобы перебирать по очереди все числа списка и запоминать наибольшее до сих пор встретившееся число. К тому моменту, когда весь список будет проверен, запомнится наибольшее число. Попробуйте нарисовать блок-схему этого алгоритма прежде, чем читать дальше. Запись А^В означает оператор присваивания, т. е. переменной А присваивается текущее значение В. Algorithm МАХ. Даны N действительных чисел в одномерном массиве R(1), R(2),..., R(N), найти такие М и J, что М =R (J) = шах R(K). 1 < K<N В случае когда два или более элементов R имеют наибольшее значение, запоминается наименьшее значение J. Шаг 0. [Установка в начальное состояние, или инициализация] Set M<-R (1); and Уч-1. Шаг 1. [N= 1?] If N=l then STOP fi l). Ч В этом алгоритме fi и od используются соответственно для обозначения конца конструкций if и do. Более детально это будет обсуждаться в разд. 2.1, Шаг 2. {Проверка каждого числа] For К-+-2 to N do шаг 3 od; and STOP. Шаг 3. [Сравнение] If M<CR(/()then set M+-R(K); and fi (теперь M •— наибольшее число из проверенных, а К — его номер в массиве). Алгоритм МАХ не закодирован на каком-то языке, а записан в форме, которую легче воспринять; он выражен в виде шагов, которые легко реализуются в каждом общепринятом языке программирования. От такого представления нетрудно перейти к кодовой форме. Однако так бывает не всегда. Некоторые алгоритмы слишком сложны, чтобы перейти за один шаг от предварительного словесного описания к кодам машины. Может потребоваться ввести по крайней мере один промежуточный этап разработки. 1.3. Основные этапы полного построения алгоритма Теперь мы кратко рассмотрим основные этапы, перечисленные в конце разд. 1.1. Прежде всего определим назначение каждого этапа и выясним, как эти этапы объединяются в единое целое. Постановка задачи Прежде чем мы сможем понять задачу, мы должны ее точно сформулировать. Это условие само по себе не является достаточным для понимания задачи, но оно абсолютно необходимо. Обычно процесс точной формулировки задачи сводится к постановке правильных вопросов. Перечислим некоторые полезные вопросы для плохо сформулированных задач: Понятна ли терминология, используемая в предварительной формулировке? Что дано? Что нужно найти? Как определить решение? Каких данных не хватает и все ли они нужны? Являются ли какие-то имеющиеся данные бесполезными? Какие сделаны допущения? Возможны и другие вопросы в зависимости от конкретной задачи. Часто после получения полных или частичных ответов на некоторые из вопросов их приходится ставить повторно. Пример. Джек — агент но продаже компьютеров (коммивояжер); на его территории 20 городов, разбросанных по всему Техасу. Компания возмещает ему только 50% стоимости деловых автомобильных поездок. Джек вычислил, сколько ему будет стоить переезд на машине между каждыми двумя городами на его территории. Ему, естественно, хотелось бы снизить свои дорожные расходы. Что дано? Исходная информация задана в виде перечня городов на территории Джека и соответствующей матрицы стоимостей, т. е. двумерного массива с элементами ctj, равными стоимости переезда из города i в город /. В данном случае матрица стоимостей имеет 20 строк и 20 столбцов. Что мы хотим найти? Мы хотим помочь Джеку снизить его дорожные расходы. Это звучит несколько туманно. Действительно, вопрос о том, каким будет решение, выглядит неуместным. Обдумав ситуацию, мы придем к выводу, что ничего не можем сделать без дополнительной информации от Джека. Имеет ли Джек в одних городах больше покупателей, чем в других? Если да или если есть какие-то особые покупатели, то Джек, возможно, захочет посещать какие-то города чаще. Могут быть и такие города, в которые Джек специально не поедет, а заедет туда, когда окажется в соседнем городе. Другими словами, нам надо знать больше о приоритетах Джека и учитывать предпочтения при составлении графика поездок. Поэтому мы возвращаемся к Джеку и требуем у него дополнительную информацию. Он сообщает, что хотел бы иметь маршрут, начинающийся и оканчивающийся в его базовом городе и проходящий по одному разу через все остальные города на его территории. Следовательно, нам требуется список городов, содержащий каждый город только один раз, за исключением базового города, который стоит в списке первым и последним. Порядок городов в этом списке представляет собой маршрут, по которому Джек должен объезжать города па своей территории. Сумма стоимостей проезда между каждыми двумя последовательными городами списка -— это общая стоимость маршрута, представленного списком. Мы решим задачу Джека, если представим ему список с наименьшей возможной общей стоимостью. Это хорошая исходная постановка задачи. Мы знаем, что мы имеем и что хотим найти.
|
|||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2016-09-20; просмотров: 813; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.139.236.89 (0.147 с.) |