Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
% Вначале текущее множество рёбер устанавливается пустым.
% Затем, пока это возможно, проводится следующая операция: из всех рёбер, добавление которых
% к уже имеющемуся множеству не вызовет появление в нём цикла, выбирается ребро минимального веса
% и добавляется к уже имеющемуся множеству. Когда таких рёбер больше нет, алгоритм завершён.
% Пример запроса (картинка http://www.youtube.com/watch?v=vm_9-vnV7PE)
example(Res) :- city([edge(1,3,13), edge(1,4,19),edge(3,2,20),edge(4,2,4), edge(2,5,15), edge(4,7,17),edge(5,7,8),edge(5,6,22),edge(7,6,10)], Res).
city(DistanceCities, ResultConfiguration) :- city(DistanceCities, [], ResultConfiguration).
% city(DistanceCities, ExistingConfiguration, ResultConfiguration)
% ищем минимальное ребро : если найдено, то 1) продолжаем выделять ребра,
% добавив найденное к существующим ,если не найдено - 2) алгоритм завершен
city(Distances, Existing, ResultConfiguration) :-
(pick_minimum_edge_wo_cycle(Distances, Existing, Edge) ->
city(Distances, [Edge | Existing], Result), ResultConfiguration = [Edge | Result] ;
ResultConfiguration = [] ) .
% Выбирает минимальное ребро не образующее цикла,
% Нисходящая рекурсия сравнивает уже выбранное допустимое минимальное ребро
% на предыдущих шагах (1-й выбор []) с текущим ребром, проверяя допустимость
% Восходящая рекурсия возвращает результат и проверяет, что не [].
pick_minimum_edge_wo_cycle(Distances, Existing, Edge) :-
pick_minimum_edge_wo_cycle(Distances, Existing, [], Edge), not(Edge = []).
pick_minimum_edge_wo_cycle([], _, ToCompare, ToCompare).
pick_minimum_edge_wo_cycle([Edge|L], Existing, ToCompare, Result) :- (
(less_edge(Edge, ToCompare), no_cycle(Edge, Existing) ) ->
pick_minimum_edge_wo_cycle(L, Existing, Edge, Result) ;
pick_minimum_edge_wo_cycle(L, Existing, ToCompare, Result) ).
% Сравнение ребер - возвращает true если 1-е меньше 2-го
less_edge(edge(_X1, _Y1, Z1), edge(_X2, _Y2, Z2)) :- Z1 < Z2.
less_edge(edge(_X1, _Y1, _Z1), []).
% Проверка что нет цикла
no_cycle(edge(X, Y, _), Existing) :- not(search(X, Y, Existing, [])).
% реализует поиск пути от вершины Х к вершине Y
% алгоритм поиска - поиск в глубину.
search(X, Y, Edges,_):- member(edge(X,Y,_), Edges).
search(X, Y, Edges,_):- member(edge(Y,X,_), Edges).
search(X, Y, Edges, PassedVertices):- member(edge(X,Z, _),Edges),
not(member(Z, PassedVertices)), search(Z,Y,Edges,[Z|PassedVertices]).
search(X, Y, Edges, PassedVertices):- member(edge(Z,X, _),Edges),
not(member(Z, PassedVertices)), search(Z,Y,Edges,[Z|PassedVertices]).
Задача Прима-Краскала на языке Пролог