Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab1_1hse.doc
Скачиваний:
5
Добавлен:
08.02.2015
Размер:
102.5 Кб
Скачать

Самостоятельная часть работы

  • Составьте протокол поиска другой целевой вершины.

  • Поменяйте порядок расположения фактов. Убедитесь, что порядок обхода, но не результат, зависит от порядка расположения фактов в программе.

  • Добавьте транзитивные рёбра, например, edge(d,i), и убедитесь, что программа отыскивает все альтернативные пути. Объясните, как это происходит .

  • Введите цель в тексте программы посредством команды Goalpath(a,i,L). Как увидеть теперь результат на экране? Как вывести все альтернативные решения?

1.1.2. Обратный поиск (от целевой вершины к исходной).

Приведенная ниже программа обратного поиска rev_search на первый взгляд очень напоминает предыдущую, изменено только имя предиката:

rev_search(X,X,[X]).

rev_search(X,Y,[Y|P]):-edge(Z,Y), rev_search(X,Z,P).

Отличие заключается, во-первых, в порядке расположения аргументов предиката edge. Здесь свободная переменная Z является 1-м аргументом, т.к. отыскивается родительская вершина для текущей вершины Y. Поэтому программа будет отыскивать по фактам edge вершину Z, являющуюся прямымпредшественникомданной вершины Y (а не потомком вершины Х, как было ранее).

Во-вторых, изменён порядок аргументов в вызывающем предикате rev_search(X,Z,P): на первом месте - заданная начальная вершина X (так как ищем путь к нейотY). Второй аргумент - найденная с помощью факта edge очередная родительская вершинаZискомого обратного пути.

В-третьих, в головном предикате rev_search(X,Y,[Y|P]) в список добавляется вершинаY, а неX, как было в прямом поиске.

Рассмотрим протокол поиска, задав на том же графе (см. п.1.1.1.) аналогичную цель поиска rev_search(a,i,L). Первое предложение не подходит, потому чтоa≠i.

По второму предложению правила rev_search, подставляя в него каждый раз значения переменных и констант из очередной цели, а вместо переменнойZ- её значение из фактовedge, имеем:

rev_search(a, i, [i|P]): - edge(f, i), rev_search(a, f, P).

rev_search(a, f, [f|P1]): - edge(c, f), rev_search(a, c, P1).

rev_search(a, c, [c|P2]): - edge(a, c), rev_search(a, a, P2).

Теперь подходит первое предложение:

rev_search(a,a,[a])., т.е. P2=[a].

Возврат рекурсии позволяет означить переменные в стеке:

P1 = [c|P2] = [c, a]; P = [f|P1] = [f, c, a]; L = [i|P] = [i, f, c, a].

Список пути получается обратным. При выводе на печать можно преобразовать его в прямой, но эту задачу решите самостоятельно.

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

Если граф имеет транзитивные рёбра, и как минимум у одной из вершин окажется более одной предшествующей, программа должна отыскать все альтернативные пути из Y в X.

Самостоятельная часть работы.

  • Напишите протокол поиска пути от Yк Х.

  • Введите в граф транзитивные рёбра, например, edge(d, i).

  • Попытайтесь повысить полезность программы lab1_1.pro, придав ей следующие дополнительные функции:

  • определения корневой вершины графа;

  • вывода на печать прямого списка пути.

Задание №1.2. Поиск пути в ориентированном графе с циклом.

Рассмотрим циклический граф и соответствующий список фактов:

edge(x,y).

x

edge(y,z).

edge(z,x).

y

z

edge(y,u).

edge(z,v).

v

u

Если поставить цель path(x, v, Path) и применить программу из задания №1.1, то решение найдено не будет, так как возникает цикл x,y,z,x,y,z..., ведущий к переполнению стека. В данном случае решение можно получить, если факт edge(z,x) поставить в конец списка. Но такой прием не всегда очевиден, особенно при большом графе и не единственном цикле.

Общее решение состоит во введении в предикат path четвертого аргумента Vis, представляющего собой список посещенных в процессе поиска вершин (visited). При этом в тело правила рекурсии path следует ввести проверку дополнительного условия о не членстве очередной проверяемой вершины N в этом списке cпомощью правилаmember. Правила будут выглядеть теперь следующим образом:

way(X, Y, P): - path(X, Y, P, [X]).

path(X, X, [X],_).

path(X, Y, [X|P], Vis,]): - edge(X, N), not(member(N, Vis)), path(N, Y, P, [N|Vis]).

member(X, [X|_]).

member(X, [_|Ys]): - member(X, Ys).

Целевым здесь является предикат way. Поставим цель: way(x, v, Path).

Первое предложение приведенного набора правил переопределяет цель, вводя четвёртый аргумент - список посещённых вершин - и задаёт его начальное значение Vis = [X].

Второе предложение является обычным условием окончания рекурсии. Третье предложение – основное рекурсивное правило поиска. Правило member проверяет членство текущей вершины N в списке Vis. Если её нет в этом списке, member терпит неудачу, а выражение not(member(N, Vis)) принимает значение «истина». Вершина N добавляется в голову списка Vis последним предикатом path в теле основного правила, и идет рекурсивное обращение к голове того же правила в том случае, если очередная проверяемая вершина N не совпадёт с конечной вершиной пути Y. Если такое совпадение происходит, то идет обращение к условию окончания рекурсии (предложению 2 набора правил). Аргументы этого правила принимают значения (в данном примере) path(v,v,[v],Vis), где Vis есть список всех посещенных вершин на пути из x в v. Все правило принимает значение «истина», и прямой ход рекурсии на этом заканчивается. Далее идёт возврат рекурсии, при этом в голову списка [Х|P] на каждом “этаже” стека по очереди добавляются в обратном порядке пройденные вершины, а список Vis, наоборот, укорачивается до начальной вершины [X], в данном случае до [x]. Тело первого предложения правила в итоге принимает значение «истина», а значит, истинна и цель way(x, v, Path), где в переменной Path будет содержаться искомый путь.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]