找到船上点之间的所有路径

时间:2013-06-21 16:39:38

标签: haskell

在本主题中: How find path at the m x n table 我发现了如何在两点之间生成路径,这就是代码:

go m n (i,j) = 
   [ (i+1,j) | i<m ] ++
   [ (i-1,j) | i>1 ] ++
   [ (i,j+1) | j<n ] ++
   [ (i,j-1) | j>1 ] 

-- isEndOfPath p q = (p == q)

genPath p q acc m n input buf = g p q acc buf where
  g p q acc buf | p==q = [(acc)]   -- return acc, buf
  g p q acc buf = [s
                     | r <- go m n q, notElem r buf, notElem r acc, 
                       notElem r input,
                       s <- genPath p r (r:acc) m n input (r:buf)] ++
                  [s
                     | r <- go m n q, notElem r acc, 
                       r==p,
                       s <- genPath p r (r:acc) m n input (r:buf)]

例如,我们可以在2x2上搜索从(2,2)到(1,1)的路径。因此,我们可以将其称为

genPath (2,2) (1,1) [(1,1)] 2 2 [(3,3),(1,1)] [(1,1)] 

我们有结果

[[(2,2),(2,1),(1,1)],[(2,2),(2,1),(1,1)],[(2,2),(1,2),(1,1)],[(2,2),(1,2),(1,1)]]

所以我们有正确的路径。

现在我将找到成对点之间的所有路径。在Prolog中,它非常简单,我对此没有任何问题。所以,我可以告诉你我的算法和代码:

第一个谓词 - 当我们找到所有路径时,我们将其返回:

genAllPaths([],A,A,_,_,_,_).

否则,我们必须递归地生成路径。所以,我们在第一对之间找到路径,然后我们可以搜索其他路径:

genAllPaths([(I1,J1),(I2,J2)|T],Acc,S,M,N,Input,Bufor) :-
    genPath((I1,J1),(I2,J2),[(I2,J2)],X,M,N,Input,[(I2,J2)|Bufor],NewBufor),
    genAllPaths(T,[X|Acc],S,M,N,Input,NewBufor).

如果你不明白,请问我。

因此,现在我将在哈斯克尔进行。我试过了,但是我又遇到了很多问题。如果你知道怎么做并希望帮助我 - 我将非常感激。

1 个答案:

答案 0 :(得分:1)

go m n (i,j) = 
   [ (i+1,j) | i<m ] ++
   [ (i-1,j) | i>1 ] ++
   [ (i,j+1) | j<n ] ++
   [ (i,j-1) | j>1 ] 

genPath p q acc m n input buf = g p q acc buf  -- return all solutions
  where
    g p q acc buf | p==q = [(acc,buf)]   -- return acc, buf
    g p q acc buf = [s |
                       r <- go m n q, notElem r buf, notElem r acc, 
                       notElem r input,
                       s <- g p r (r:acc) (r:buf)] ++
                    [s |
                       r <- go m n q, notElem r acc, 
                       r==p,
                       s <- g p r (r:acc) (r:buf)]

您的新代码:

genAllPaths([],A,A,_,_,_,_).

genAllPaths([(I1,J1),(I2,J2)|T],Acc,S,M,N,Input,Bufor) :-
  genPath((I1,J1),(I2,J2),[(I2,J2)],X,M,N,Input,[(I2,J2)|Bufor],NewBufor),
  genAllPaths(T,[X|Acc],S,M,N,Input,NewBufor).

直接将文本翻译成Haskell是:

genAllPaths points acc m n input buf = g points acc buf where
  g  []     acc  _  = [acc]
  g (p:q:t) acc buf = 
    let sols = genPath p q [q] m n input (q:buf) -- => [(x,newbuf)]
    in concat [g t (x:acc) newbuf | (x,newbuf) <- sols]

另一种写作方式是

genAllPaths points acc m n input buf = g points acc buf where
  g  []     acc  _  = [acc]
  g (p:q:t) acc buf = 
    genPath p q [q] m n input (q:buf) >>= (\ (x,newbuf) ->
    g t (x:acc) newbuf )

这使用列表monad中的 bind 运算符>>=。还有do符号,

genAllPaths points acc m n input buf = g points acc buf where
  g  []     acc  _  = return acc    -- same as writing `[acc]`, for list monad
  g (p:q:t) acc buf = 
    do
      (x,newbuf) <- genPath p q [q] m n input (q:buf) 
      g t (x:acc) newbuf 

表示在没有明确使用 bind 的情况下进行相同的计算。 List monad通过将所有可能的选择表示为列表来表示非确定性计算。真实的表示将使用具有不可预测顺序的无序列表;正常的Haskell列出了诱导顺序,但Prolog从左到右的自上而下的策略也是如此。

由于Haskell是懒惰的,因此逐个生成结果解决方案等同于Prolog的回溯搜索,take 1可用于模拟cut