我有一个装满事实的数据库,例如:
overground(newcrossgate,brockley,2).
overground(brockley,honoroakpark,3).
overground(honoroakpark,foresthill,3).
overground(foresthill,sydenham,2).
overground(sydenham,pengewest,3).
overground(pengewest,anerley,2).
overground(anerley,norwoodjunction,3).
overground(norwoodjunction,westcroydon,8).
overground(sydenham,crystalpalace,5).
overground(highburyandislington,canonbury,2).
overground(canonbury,dalstonjunction,3).
overground(dalstonjunction,haggerston,1).
overground(haggerston,hoxton,2).
overground(hoxton,shoreditchhighstreet,3).
纽克罗斯盖特到布罗克利需要2分钟。
然后我创建了一个规则,这样如果我输入查询istime(newcrossgate,honoakpark,Z)。那么prolog应该给我在这两个车站之间旅行所需的时间。(我制定的规则是为了计算任意两个站点之间的距离,而不仅仅是相邻站点)。
istime(X,Y,Z):- istime(X,Y,0,Z); istime(Y,X,0,Z).
istime(X,Y,T,Z):- overground(X,Y,Z), T1 is T + Z.
istime(X,Y,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
istime(X,Y,Z):- overground(X,B,T), istime(B,X,T1), Z is T + T1.
它似乎非常适合纽克罗斯盖特到前几个车站,例如纽克罗斯gate到森林山或锡德纳姆。然而,在测试了纽克罗斯盖特到西克罗伊登的26分钟后,我尝试了纽克罗斯盖特到水晶星系,普洛斯说应该需要15分钟。。。尽管事实上它是西克罗伊登之后的下一个车站。很明显,这里出了问题,但它对大多数电视台都有效,偶尔也会出现错误,有人能告诉我出了什么问题吗?:S
这与您之前的问题本质上是相同的问题,唯一的区别是您需要在前进的过程中积累时间。
我看到的一件事是,您的"公共"谓词istime/3
试图做得太多。它所要做的就是为累加器设定种子并调用工作谓词istime/4
。由于您正在双向查找路由/时间,因此公共谓词应该只是
istime( X , Y , Z ) :- istime( X , Y , 0 , Z ) .
istime( X , Y , Z ) :- istime( Y , X , 0 , Z ) .
以上基本上是您的istime/3
谓词的第一个子句
istime(X,Y,Z):- istime(X,Y,0,Z); istime(Y,X,0,Z).
istime/3
的其余子句,递归子句:
istime(X,Y,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
istime(X,Y,Z):- overground(X,B,T), istime(B,X,T1), Z is T + T1.
应该适当地是istime/4
的一部分并且具有累加器。这就是你的问题所在。
再给它一次机会,编辑你的问题以显示下一次迭代。如果你仍然搞不清楚,我会给你看一些不同的方法。
一些提示
你的"worker"谓词可能看起来很像你之前的"在两个站点之间找到一条路线"练习,但它会有一个额外的参数,即经过时间的累加器。
有两种特殊情况。如果你使用你在"寻找两个车站之间的路线"解决方案中使用的方法,特殊情况是
- A和B直接相邻
- A和B通过至少一个中间挡块连接
还有另一种方法,可以被描述为使用前瞻性,在这种情况下,特殊情况是
- A和B是一样的,在这种情况下你就到了
- A和B不是并且通过零个或多个中间挡块连接
FWIW,你不一定期望经过时间最短或跳数最少的路线是第一个找到的解决方案。回溯将生成所有路线,但找到它们的顺序与事实存储在数据库中的顺序有关。图的最小成本搜索完全是另一回事。
您是否尝试过使用;
循环浏览答案?26分钟是纽克罗斯盖特和西克罗伊登之间的最短时间。。。
编辑:我的坏!显然,较短的结果是由于您的代码中的一个错误(请参阅我对第4条的评论)。然而,你的代码是正确的,15分钟是纽克罗斯盖特和水晶星系之间最短的路线。只是因为有一条路线从纽克罗斯盖特到维斯克罗伊登,然后是水晶星系,这并不意味着这是最短的路线,或者你的程序将首先产生的路线。
更新:如果你在寻找某些路线的答案时遇到问题,我建议将第3子句更改为:
istime(X,Y,_,Z):- overground(X,A,T), istime(A,Y,T1), Z is T + T1.
原因很简单:你的第一个子句用Y交换X,这很好,因为这样你就说路线是对称的。然而,第三条并没有从中受益,因为它从来没有被交换的一条调用过。忽略第三个参数(你无论如何都没有使用),从而让第一个子句调用第三个可能会解决你的问题,因为以前没有使用的一些有效路由现在会被使用。
(还有:我同意Nicholas Carey的回答,最好使用第三个参数作为累加器;但正如我所说,暂时忽略它可能会起作用)
要使其工作,您需要执行上一子句中所述的两个旅程的相反操作。保持谓词的原样,istime(X,Y,Z),然后再生成一个包含反向行程的子句。通过这种方式,它可以与所有电台一起工作。(试用和测试)