Prolog:骑士的最短路径

时间:2016-12-17 23:11:07

标签: prolog combinatorics

嗨,所以在我被告知这个问题被多次询问之前,我已经查看过一堆问题,但没有一个与Prolog有关。这就是我遇到的困难。

我试图找到棋盘上两点之间的最短路径。我的代码专门针对骑士。到目前为止,这是我的代码:

move1( (X1,Y1), (X2,Y2) ) :- up1( X1, X2 ), up2( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- up2( X1, X2 ), up1( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- up1( X1, X2 ), down2( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- up2( X1, X2 ), down1( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- down1( X1, X2 ), up2( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- down2( X1, X2 ), up1( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- down1( X1, X2 ), down2( Y1, Y2 ).
move1( (X1,Y1), (X2,Y2) ) :- down2( X1, X2 ), down1( Y1, Y2 ).

up1( U, V ) :- successor( U, V ).
up2( U, W ) :- successor( U, V ), successor( V, W ).
down1( U, V ) :- up1( V, U ).
down2( U, V ) :- up2( V, U ).

successor( 1, 2 ).
successor( 2, 3 ).
successor( 3, 4 ).
successor( 4, 5 ).

edge((X1,Y1) , (X2,Y2)) :- move1( (X1,Y1), (X2,Y2) ).

path((X1,Y1), (X2,Y2),N,[(X1,Y1), (X2,Y2)]) :- N > 0, edge((X1,Y1), (X2,Y2)).
path((X1,Y1), (X3,Y3),N,[(X1,Y1)|P1]) :- N > 0, N1 is N-1, path((X2,Y2), (X3,Y3),N1,P1), edge((X1,Y1), (X2,Y2)), nonmember((X1,Y1),P1).

shortest((X1,Y1),(X2,Y2),P) :- path((X1,Y1),(X2,Y2),24,P),!.

visit((X1,Y1),P,N) :-  path((X1,Y1), (X2,Y2),N,P),N2 is N+1,len(P,N2).

len([],0).
len([_|T],N)  :-  len(T,X),  N is X+1. 

nonmember(X,[]).
nonmember(X,[U|Y]) :- X \= U, nonmember(X,Y).

如您所见,我只找到第一条路径而不是最短路径。我不知道如何在prolog中编码并找到一种方法来获得所有最短的路径。我正在考虑制作一个列表,列出所有可能的路径,然后找到最短但我似乎无法编写代码。

findAll((X1,Y1),(X2,Y2),P,L) :- path((X1,Y1),(X2,Y2),24,P),length(P,L).

给我每条路的长度,但我不知道该怎么做。 任何有关如何在Prolog中编码以找到最短路径的帮助都将非常有用,而且正是我所寻求的。

1 个答案:

答案 0 :(得分:0)

要按照您的方法来计算所有路径并找到最小路径,我会选择aggregate库。

但首先,我建议对代码进行一些清理,因为我不确定它是否会以这种方式正常工作(但我刚刚检查过很快)。

特别是,您希望到达谓词path((X1, Y1),(X2, Y2),Path),该谓词允许枚举所有路径(如果您多次重试)然后停止。一旦所有路径都耗尽,你的东西似乎无限循环。 您可以找到有关如何枚举所有非循环路径here的一些启示。

修复后,您可以通过以下方式使用aggregate/3

:-use_module(library(aggregate)).    

find_min(Start, End, Path) :-
    aggregate(
        min(Length, Path),
        (path(Start, End, Path), length(Path, Length)),
        min(_,P)
     ).
然后

find_min(Start, End, Path)将允许您枚举从一个单元格到另一个单元格的所有最短路径。 请注意,从StartEnd可能有多条最短路径;这将返回所有最短路径,而不仅仅是一条路径。

另一个可能的解决方案是实现Djikstra的最短路径算法,这可能比枚举所有路径和找到最小路径算法更有效,就像我们在这里做的那样。但这将是一种完全不同的方法。

编辑:使用小型主板4x4或5x5,然后枚举所有路径并找到最小方法可能会起作用,但在8x8主板上,复杂性将变得无法控制。 在这里,最好的方法是改变你的方法和实现,例如,Djikstra的算法。