所以我试图使用递归方法来找到两个人之间的路径。这是快速背景:
我定义了一些事实in(X,Y)
。那表明谁是相关的,即。 in(person1,project1)
,in(person2,project1)
等等。现在任何两个人都是相关的,如果他们在彼此的同一个项目中,或者他们之间有人的链接路径。例如,p1工作于A p2工作于A和B,p3工作于B,因此存在从p1到p3到p2的路径。这些路径可以是任意长度。
我试图递归地解决这个问题(不要看其他任何方式),但是有一个恼人的问题:
related(A,B) :-
in(A,X),
in(B,X),
not(A=B).
chain(A,B) :-
related(A,B).
chain(A,B) :-
related(A,Y),
chain(Y,B).
问题是路径可以重复。它可以从p1到p2回到p1无尽的时间。一个人不应该超过1次。
我尝试使用我添加的列表修复此问题。如果一个人已经在列表中,则无法再次添加:
related(A,B,L) :-
in(A,X),
in(B,X),not(A=B).
chain(A,B,L) :-
related(A,B,L).
chain(A,B,L) :-
related(A,Y,L),
not(member(Y,L)),
append(L,[Y],Q),
chain(Y,B,Q).
它有点奏效,但造成了大量的随机错误,多次重复一些人,有些只重复一次,然后失败。这种方法看起来不错吗?我是否完全使用了错误列表?
谢谢。
答案 0 :(得分:0)
第一次改进。您是在寻找所有关系链还是想检查是否存在一个关系链?在第一种情况下添加一个剪切。
chain(A,B) :-
related(A,B), !.
chain(A,B) :-
related(A,Y),
chain(Y,B).
在第二种情况下,Prolog完全按照要求去做,就是找到所有可能的链。
请发布导致问题的查询,以便我们可以一起推理并改进解决方案。
答案 1 :(得分:0)
这是一种替代方法,可能效率较低,但相当一般,基于固定点计算。
connected(Found, Connected) :-
collect(Found, [], Ext),
( Ext == Found
-> Connected = Found
; connected(Ext, Connected)
).
collect([], Set, Set).
collect([E|Es], Set, Fix) :-
extend(E, Set, Ext),
collect(Es, Ext, Fix).
extend(E, Set, Ext) :-
directly(E, DirectConn),
ord_union(DirectConn, Set, Ext).
directly(A, DirectConn) :-
setof(B, P^(in(A, P), in(B, P)), DirectConn).
我们必须使用已排序的列表调用connected(Found,Connected),然后循环直到无法扩展该set。例如,使用此测试数据
in(anna, project1).
in(bob, project1).
in(bob, project2).
in(chris, project2).
in(dan, project3).
?- connected([bob],L).
L = [anna, bob, chris].
?- connected([dan],L).
L = [dan].
我允许直接/ 2获得身份,即
?- directly(X,Y).
X = anna,
Y = [anna, bob] ;
...
X = dan,
Y = [dan].
答案 2 :(得分:0)
我觉得我从来都不是很清楚,但我最终解决了这个问题。我把代码放在下面。
真正重要的是一个有效的notchain谓词,然后确保我正确地做了追加。我还创建了一个notsame谓词来替换not(A = B)。代码如下。大多数答案是确保在列表附加的内容周围有[]。
附近没有正确附加的正确[]notchain(X,L): -
构件(X,L),!,失败。
notchain(X,L)。
然后:
链(A,B,L): -
相关(A,B), 附加(L,[A],Q), 追加(Q,[B],Z), 写(最终),writeln(Z)。
链(A,B,L): - notchain(A,L), 附加(L,[A],Q), 相关(A,Y), 链(Y,B,Q)。
这用于相关:
notsame(A,B): -
(A = B),!,失败。notsame(A,B)。