这是我找到的代码,并且已在我制作的另一个post中进行了修复。
s(a, b).
s(a, c).
s(b, g).
s(b, f).
s(c, r).
s(c, e).
goal(g).
solve( Start, Solution) :-
breadthfirst( [ [Start] ], Solution).
breadthfirst( [ [Node | Path] |_], [Node | Path] ) :-
goal( Node).
breadthfirst( [ [N | Path] | Paths], Solution) :-
bagof([M,N|Path],
( s( N, M), \+ member( M, [N | Path] ) ), NewPaths),
%conc( Paths, NewPaths, Pathsl), !,
append(Paths, NewPaths, Pathsl), !,
breadthfirst( Pathsl, Solution);
breadthfirst( Paths, Solution).
但是,我发现输出是:
?- solve(a,S).
S = [g, b, a] ;
我掌握了所有事实,并绘制了一棵树来表示它们,在树中,我们得到a
给出的b
和c
处于同一级别,即第1级因此,应该首先访问它们。然后,在g
的第二级访问b
。
所以输出应该是:
?- solve(a,S).
S = [g, c, b, a] ;
但是它没有给我输出,我也不知道为什么。
现在,还有一个反转输出的问题,如果也解决了,我将不胜感激。
答案 0 :(得分:2)
它没有给我输出,我也不知道为什么。
您的代码给出了正确的答案,如我先前的answer所述。
?- solve(a,S).
S = [g, b, a] ;
问题不是代码给出的答案,但我相信您将从事实中了解算法的工作方式或图形的布局。
在将问题转换为代码之前,使用纸和笔处理问题是一个明智的决定。
这是图形形式的图形,其根(a
)在顶部。
a Level 0
/ \
b c Level 1
/ \ / \
g f r e Level 2
请注意,从a
到g
的最短路径是a
,b
,g
,而不是a
,{{1} },b
,c
。即使g
已连接到c
,它也不在从a
到a
的路径上,因此也不是解决方案的一部分。
您是正确的,因为使用广度优先搜索(BFS)从g
开始,然后处理与其连接的 ALL 节点,这些节点显示在Level 0
中。然后,对Level 1
中的每个节点执行相同的操作,创建Level 1
,然后对每个新级别再次重复。
在处理每个节点时,BFS只会查找尚未访问的与该当前节点连接的任何节点,并将其所需的任何信息记录在表或其他数据结构中。如果您的示例在每个顶点上包括权重,则到达当前正在处理的节点的成本将与当前节点一起记录在数据结构中。访问节点以处理节点与作为从一个节点到另一节点的最短路径的一部分而访问节点不同。
考虑这一点的另一种方法是BFS和深度优先搜索(DFS)应该都给出相同的答案,不同之处在于算法。如果对此使用DFS,则将得到相同的答案Level 2
,a
和b
,而没有g
。
c
来自评论:
好的,我知道了,所以算法的实际工作是在我打印出包括c的代码时进行的,但是当它想打印最终路径时,它将排除c,因为它不在路径上。
我不同意。
运行带有SWI-Prolog中跟踪功能的查询
dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).
?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.
在
line 1 [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), \+member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), \+member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append([], [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append([], [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), \+member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), \+member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), \+member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), \+member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), \+member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), \+member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), \+member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), \+member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), \+member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), \+member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), \+member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), \+member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1([], _12870)
line 94 Fail: (16) breadthfirst_1([], _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.
它显示了访问起始节点line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), \+member(_13076, [a])), _13134)
的结果,起始节点a
只是路径a
,并且在已知路径列表中是[a]
。
在
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), \+member(_13076, [a])), [[b, a], [c, a]])
对于路径[a]
,通过使用列表顶部的项目并访问其中一个未被访问的邻居,然后将该新路径添加到新列表中,来创建一个新列表。
所以
使用路径为[a]
并使用列表a
开头的项目访问其邻居之一s(a,b)
,并将新路径添加到新列表[[b,a]]
中。
使用路径[a]
,并使用列表a
开头的项目,访问其邻居之一s(a, c).
,并将新路径添加到新列表{{1} }。
在
[[b,a],[c,a]]
对于路径line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), \+member(_13198, [b, a])), [[g, b, a], [f, b, a]])
,通过使用列表顶部的项目并访问其中一个未被访问的邻居,然后将该新路径添加到新列表中,来创建一个新列表。
所以
使用路径为[b, a]
并使用列表[b, a]
开头的项目访问其邻居之一b
,并将新路径添加到新列表s(b, g).
中。
使用路径[[g, b, a]]
,并使用列表[b, a]
开头的项目,访问其邻居之一b
,并将新路径添加到新列表s(b, f).
中。
请注意,答案[[g, b, a], [f, b, a]]
现在在新列表中,但路径中没有[g, b, a]
。
在
c
所有路径均已创建
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
使用所有[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]
事实,但答案为s/2
的路径中却没有[g, b, a]
。
为什么从conc / 3更改为append / 3?
即使这不是您的问题之一,我也需要为阅读此问题的其他人回答,尤其是第一次自行学习Prolog的人。
这是我与c
和conc/3
相关的事件的版本,如果还有其他故事可以说明的话;如果需要的话,我什至会把它作为已发布的问题来询问。
关于入门学习/教学的最好甚至最好的书之一是Ivan Bratko撰写的“人工智能的Prolog编程”。 (WorldCat)(Amazon)。
当初次学习Prolog时,人们倾向于在列表数据结构中度过一生,并获得append/3
的健康饮食,但在书中,他选择让学生创建自己的append/3
版本并将其命名为append/3
。因此,整本书都使用conc/3
,而几乎没有使用conc/3
。现在,这些人已经习惯了append/3
并开始使用它编写代码,发布代码等,并且它具有很高的感染力,您碰巧发现了它。因此,我为您的代码提供了补救措施。
输出反转的问题。
使用递归解决问题时,通常将中间结果存储在堆栈中。根据堆栈上的顺序,结果是正确的顺序,也可以是相反的顺序。
有几种方法可以使递归结果以正确的顺序返回。
对于大多数初学者来说,是获得结果,并且如果需要的话,只需反转结果即可。对于Prolog,如果结果是列表,则reverse/2有效。
conc/3
reverse / 2的谓词
?- reverse([g, b, a],R).
R = [a, b, g].
当您遇到更大的问题时,即使在不同的谓词调用之间不断颠倒结果也会开始增加时间。在函数式编程中尤其如此。
另一种方法是通过累加器。为了说明这一点,我将使用这个简单的反向版本。
?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, [], B, B).
true.
?- listing(reverse/4).
lists:reverse([], A, A, []).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).
true.
第一个子句将累加器初始化为空列表reverse_2(L,Result) :-
accumulator_reverse(L,[],Result).
accumulator_reverse([],A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).
,以与[]
一起使用
accumulator_reverse/3
其他两个子句仅以该子句为基本情况递归处理列表
reverse_2(L,Result) :-
accumulator_reverse(L,[],Result).
,即输入列表为空(accumulator_reverse([],A,A).
)和
此条款
[]
将列表拆开accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).
(又称为AKA解构函数),并将头[H|T]
附加到累加器H
(又称为AKA构造函数)上。
通过
处理列表[H|A]
原始列表变得越来越小,因为总是从列表中删除头,并且累加器不断增长,因为列表中的头总是被添加到累加器。由于解构列表的顺序(从前到后)和构建累加器的顺序(从后到前),列表变得相反。
通常,当您查看重构的Prolog代码时,如果您看到递归和类似
的基本情况,accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).
其中一个参数是一个空列表或bottom,另外两个参数相同,但是一个参数在调用时绑定,另一个在调用时取消绑定,看看如果累加器传递已纳入代码中。