Algorithm Prolog程序中两节点间路径数的计算

Algorithm Prolog程序中两节点间路径数的计算,algorithm,prolog,graph-theory,graph-traversal,Algorithm,Prolog,Graph Theory,Graph Traversal,我需要一些帮助来计算可以到达目标节点的组合数 我找到了寻找不同路径的程序。但最后我需要提出一些疑问 %Edge List (Knowledge Base) edge(1,2). edge(1,4). edge(2,4). edge(3,6). edge(3,7). edge(4,3). edge(4,5). edge(5,6). edge(5,7). edge(6,5). edge(7,5). edge(8,6). edge(8,7). %Program path(X,Y,[X,Y]):-

我需要一些帮助来计算可以到达目标节点的组合数

我找到了寻找不同路径的程序。但最后我需要提出一些疑问

%Edge List (Knowledge Base)

edge(1,2).
edge(1,4).
edge(2,4).
edge(3,6).
edge(3,7).
edge(4,3).
edge(4,5).
edge(5,6).
edge(5,7).
edge(6,5).
edge(7,5).
edge(8,6).
edge(8,7).

%Program

path(X,Y,[X,Y]):- edge(X,Y).
path(X,Y,[X|Xs]):- edge(X,W), path(W,Y,Xs).

-------------------------------------------------

%Query
path(1, 7, P).

%Results
Z = [1, 2, 4, 3, 6, 5, 7];
Z = [1, 2, 4, 3, 6, 5, 6, 5, 7];
.........................
但是如果我想运行一个查询,给出这些路径的数量,该怎么办呢

?-path(1, 7, count). 

should return 2

首先,您的答案是循环的,不会终止,您可以保留一个您访问过的内容列表,以避免两次访问相同的节点:

path(X,Y,L):-path(X,Y,L,[X]).

path(X,Y,[X,Y],L):- \+member(Y,L),edge(X,Y).
path(X,Y,[X|Xs],L):- edge(X,W),\+ member(W,L) ,path(W,Y,Xs,[W|L]).
现在如果你问:

?- path(1, 7, P).
P = [1, 2, 4, 3, 7] ;
P = [1, 2, 4, 3, 6, 5, 7] ;
P = [1, 2, 4, 5, 7] ;
P = [1, 4, 3, 7] ;
P = [1, 4, 3, 6, 5, 7] ;
P = [1, 4, 5, 7] ;
false.
因此,有效路径不是2,因为上述六条路径是有效的

现在要计算您可以尝试的路径:

findall(P, path(1,7,P), Paths), length(Paths, N).
正如注释中所建议的,但这不是很有效,因为您需要首先构建一个所有路径的列表并计算长度

如果您使用的是Swipl,您可以尝试故障驱动循环来计算所有可能的路径,并使用
nb_getval/2
nb_setval/2
来计算:

count(X,Y):-
            nb_setval(counter, 0),
            path(X,Y,_),
            nb_getval(counter, Value),
            New_value is Value+1,
            nb_setval(counter, New_value),
            fail;
            nb_getval(counter, Value),
            write(Value).
例如:

?- count(1,7).
6
true.

你试过什么?我试过用递归计算步骤。但结果不是预期的移动2(X,Y,N):-N是N+1,边(X,Y)。移动2(X,Y,N):-N是N+1,边(X,Z),移动2(Z,Y,N)。
N是N+1
?这没有任何意义,但在Prolog中,变量不能接地两次(使用不同的值)。在这种情况下,您需要一个新变量。例如,您可以编写
N1是N+1
。您需要编辑您的问题并添加您在那里尝试过的代码,格式正确。注释不是放代码的地方。但也就是说,从您的评论来看,您似乎在尝试计算节点遍历次数,而不是总路径数。简单的答案是
findall(P,path(1,7,P),path),length(path,N)
N
将是您的答案。如何通过列表生成路径并对其进行计数比使用
nb_setval/2
&co.生成路径并对其进行计数效率更低。?对我来说,这似乎是同样的工作量,只是一个是普通的Prolog,另一个不是。@DanielLyons,但是使用
findall
你将计算相同的东西,但是你必须将它们保存在一个列表中,这样就不会对大的输入工作(由于堆栈溢出),而且你还需要另一个O(n)最后计算长度…另一方面,在计算解决方案时,使用失败驱动循环进行计数。在这两种情况下,计算解决方案都是不可避免的。我本人在普通Prolog中没有看到具有大输入的堆栈溢出。。。原则上这可能会发生,但我对你回答的后半部分有一种“ick”反应,因为它很不符合实际。我认为nb_setval/2是最后的手段。但是,是的,对于一个大的输入,这可能是必要的。@DanielLyons,考虑一下有一个大约10^8个路径的列表(由于findall),每个路径10^6个节点,这是很多数据,这只是一个可能的例子……但是我同意在“编写普通Prolog”和避免可能的溢出之间有一个折衷方案……非常感谢。这很清楚地解释了我的疑问!:)