Пролог невзвешенного графика дистанции на 1 - PullRequest
0 голосов
/ 09 декабря 2018

Поэтому я пытаюсь найти пути и их длины для невзвешенных графиков.Вот мой код;Вы даете ему отношение, начало и конец, а также длину.Код работает, однако он возвращает длину, которая на 1 меньше необходимой.

:- use_module(library(lists)).

edge(1,2).    
edge(1,4).    
edge(1,3).    
edge(2,3).    
edge(2,5).    
edge(3,4).    
edge(3,5).    
edge(4,5).

connected(X,Y) :- 
    edge(X,Y) 
    ; 
    edge(Y,X).

path(Rel,A,B,Path,Len) :-    
       travel(Rel,A,B,[A],Q,Len),
       reverse(Q,Path).

travel(Rel,A,B,P,[B|P],L) :-    
       call(Rel, A, B), L is 1 .

travel(Rel,A,B,Visited,Path,L) :-    
       call(Rel,A,C),
       C \== B,
       \+member(C,Visited),
       travel(Rel,C,B,[C|Visited],Path,L1),
       L is L1 + 1.

Все эти ребра имеют вес / расстояние, равное 1, однако, с учетом запроса, например

?- path(connected, 1, 5, Path, Length).

каждая длинавозвращается на 1 меньше, чем должно быть.

Любые предложения полезны.

1 Ответ

0 голосов
/ 09 декабря 2018

Вместо попыток исправить способ вычисления длины пути в предикате travel из опыта я знаю, что рефакторинг кода Пролога при обработке списка для вычисления другого свойства не сложен и обычно выполняется.

Таким образом, вместо этого рефакторируется предикат reverse/2.Для рефакторинга reverse/2 нам сначала потребуется рабочий код для reverse/2:

% Reverse using accumulator
rev(List,Rev) :-
  rev(List,[],Rev) .

rev([],A,A).
rev([H|T],A,R) :-
  rev(T,[H|A],R).

Примеры rev/2

?- rev([],L).
L = [].

?- rev([a],L).
L = [a].

?- rev([a,b],L).
L = [b, a].

?- rev([a,b,c],L).
L = [c, b, a].

Теперь для рефакторинга rev/2 для вычисления длины.

rev_n(List,Rev,N) :-
  rev_n(List,[],Rev,N) .

rev_n([],A,A,0).
rev_n([H|T],A,R,N) :-
  rev_n(T,[H|A],R,N0),
  N is N0 + 1.

Примеры rev_n/2

?- rev_n([],L,N).
L = [],
N = 0.

?- rev_n([a],L,N).
L = [a],
N = 1.

?- rev_n([a,b],L,N).
L = [b, a],
N = 2.

?- rev_n([a,b,c],L,N).
L = [c, b, a],
N = 3.

Наконец, просто измените ваш код, чтобы использовать rev_n/2, и удалите ненужные части кода, которые вычислили N.

path_2(Rel,A,B,Path,Len) :-
    travel_2(Rel,A,B,[A],Q),
    rev_n(Q,Path,Len).

travel_2(Rel,A,B,P,[B|P]) :-
    call(Rel, A, B).

travel_2(Rel,A,B,Visited,Path) :-
    call(Rel,A,C),
    C \== B,
    \+member(C,Visited),
    travel_2(Rel,C,B,[C|Visited],Path).

Пример:

?- path_2(connected, 1, 5, Path, Length).
Path = [1, 2, 5],
Length = 3 ;
Path = [1, 2, 3, 5],
Length = 4 ;
Path = [1, 2, 3, 4, 5],
Length = 5 ;
Path = [1, 4, 5],
Length = 3 ;
Path = [1, 4, 3, 5],
Length = 4 ;
Path = [1, 4, 3, 2, 5],
Length = 5 ;
Path = [1, 3, 5],
Length = 3 ;
Path = [1, 3, 4, 5],
Length = 4 ;
Path = [1, 3, 2, 5],
Length = 4 ;
false.

Более практичным способом было бы просто использовать length/2

path_3(Rel,A,B,Path,Len) :-
    travel_2(Rel,A,B,[A],Q),
    reverse(Q,Path),
    length(Path,Len).

?- path_3(connected, 1, 5, Path, Length).
Path = [1, 2, 5],
Length = 3 ;
Path = [1, 2, 3, 5],
Length = 4 ;
Path = [1, 2, 3, 4, 5],
Length = 5 ;
Path = [1, 4, 5],
Length = 3 ;
Path = [1, 4, 3, 5],
Length = 4 ;
Path = [1, 4, 3, 2, 5],
Length = 5 ;
Path = [1, 3, 5],
Length = 3 ;
Path = [1, 3, 4, 5],
Length = 4 ;
Path = [1, 3, 2, 5],
Length = 4 ;
false.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...