Prolog 序言:从类图问题中删除圆
我有下面的prolog程序,我想从位置a转到位置d。我们可以通过以下路径来实现:a->b->c->d。另一个路径是:a->b->c->b->c->d等。我们如何删除“循环”路径?我试图通过使用'not(member(from_to(X,Z))'来删除它,但它似乎不起作用Prolog 序言:从类图问题中删除圆,prolog,Prolog,我有下面的prolog程序,我想从位置a转到位置d。我们可以通过以下路径来实现:a->b->c->d。另一个路径是:a->b->c->b->c->d等。我们如何删除“循环”路径?我试图通过使用'not(member(from_to(X,Z))'来删除它,但它似乎不起作用 from_to(a, b). from_to(b, c). from_to(c, d). from_to(d, c). from_to(c, b). move(X,Y,Z) :- from_to(X,Y), X \= Y,
from_to(a, b).
from_to(b, c).
from_to(c, d).
from_to(d, c).
from_to(c, b).
move(X,Y,Z) :- from_to(X,Y), X \= Y,
Z = [from_to(X,Y)].
move(X,Y,Z) :- from_to(X,K), K \= Y, move(K,Y,Z1),
Z = [from_to(X,K)|Z1],
not(member(from_to(X,_),Z)).
(如果删除行“not(member(从_到(X,Z)),程序工作正常,但输出循环路径)这里最好使用累加器:一个通过递归调用更新的变量,因此包含某种“内存”。这里累加器可以存储我们访问过的节点列表。要移动到新节点,该节点不应在列表中
因此,我们定义一个谓词move/4
,而不是move/3
,带有:
move(X,Y,Z) :-
move(X, Y, Z, [X]).
现在我们可以使用两个规则定义谓词move(S,D,Path,visted)
:
S
和D
相同,我们就完成了,不管访问的是什么,我们都将路径
与[D]
统一起来;及
from_to/2
谓词“走”到另一个节点N
,确保它不是访问的的成员,然后我们进行递归调用,将S
前置到N
访问的节点。我们在递归Z
的结果前面加上X
move(S, S, [S], _).
move(S, D, [S|Z], Visited) :-
from_to(S, N),
\+ member(N, Visited),
move(N, D, Z, [N|Visited]).
对于示例图形:
然后生成:
?- move(a, d, Z).
Z = [a, b, c, d] ;
false.
?- move(a, D, Z).
D = a,
Z = [a] ;
D = b,
Z = [a, b] ;
D = c,
Z = [a, b, c] ;
D = d,
Z = [a, b, c, d] ;
false.
?- move(A, d, Z).
A = d,
Z = [d] ;
A = a,
Z = [a, b, c, d] ;
A = b,
Z = [b, c, d] ;
A = c,
Z = [c, d] ;
false.
?- move(A, D, Z).
A = D,
Z = [D] ;
A = a,
D = b,
Z = [a, b] ;
A = a,
D = c,
Z = [a, b, c] ;
A = a,
D = d,
Z = [a, b, c, d] ;
A = b,
D = c,
Z = [b, c] ;
A = b,
D = d,
Z = [b, c, d] ;
A = c,
D = d,
Z = [c, d] ;
A = d,
D = c,
Z = [d, c] ;
A = d,
D = b,
Z = [d, c, b] ;
A = c,
D = b,
Z = [c, b] ;
false.
如果节点未“连接到自身”,例如,我们没有从a
到a
的路径,我们可以实现move
,如下所示:
move(S, D, [S|Z], V) :-
from_to(S, N),
\+ member(N, V),
move2(N, D, Z, [N|V]).
move2(S, S, [S], _).
move2(N, D, [S|Z], V) :-
move(N, D, Z, V).
您需要保留一个包含已访问节点的列表(最初为空)。另外,使用标准的
\+/1
否定运算符/谓词,而不是不推荐的非/1
谓词。路径(从u到,路径,X,Z)
使用。请注意,已访问节点的列表更加紧凑,包含的信息与从\u到/2的术语列表相同。非常感谢!我明天会发布解决方案(如果没有其他人发布)。