fork download
  1. import Data.List
  2. {-
  3. 一只青蛙正在过河。河被分成了x段并且每一段都可能存在或不存在一个石头。这只青蛙可以跳至石头上,但不能跳进水里。
  4.  
  5. 现有一个石头位置的升序列表,判断这只青蛙能否能够跳至最后一个石头,从而过河。最初青蛙在第一块石头上并且假定第一跳只能跳一段。
  6.  
  7. 如果这只青蛙之前一次跳了k段,那么它的下一跳必须是k-1、k或k+1段。注意该青蛙只能向前跳。
  8. -}
  9.  
  10. -- jump 函数 k 表示前一次跳的步数,xs为剩下的list,
  11. -- [ v + x | v <- [k-1,k,k+1], v > 0 ] 表示下一次可以有几种跳法
  12. -- ys 表示合法的跳法,如果余下的数里没有可以允许的跳法,则结束过滤掉这种。
  13. -- concatMap 将所有合法跳法分别开跳后,合并在一个列表里
  14. -- map (n:) 将合法的跳法放入到返回list中,继续下一跳:jump n ns
  15. -- ns = dropWhile (/=x+n) xs 即将余下的列表掐掉刚好跳到的那一段。
  16. jump k xs = case xs of
  17. [] -> [[]]
  18. [x] -> [[]]
  19. (x:xs) -> concatMap (\n -> map (n:) (jump n (dropWhile (/=x+n) xs))) ys
  20. where ys = map (subtract x) $ intersect [ v + x | v <- [k-1,k,k+1], v > 0 ] xs
  21.  
  22. -- frogjump 为最终的蛙跳函数,第一步必须是1,所以不为一的则返回空
  23. -- 如果可以,则第一步1需要加入到最终的所有步骤里面
  24. -- frogjump :: (Ord a, Num a) => [a] -> [[a]]
  25. frogjump [] = []
  26. frogjump [x] = []
  27. frogjump (x:y:xs)
  28. | y - x == 1 = let ys = jump 1 (y:xs) in if null ys then ys else map (1:) ys
  29. | otherwise = []
  30.  
  31. main = do
  32. -- print $ jump 1 [1,3,5]
  33. -- print $ jump 1 [1,3,4,5,6,8,12,17]
  34. print $ frogjump [0, 1, 3, 5, 6, 8, 12, 17]
  35. print $ frogjump [0, 1, 2, 3, 4, 8, 9, 11]
Success #stdin #stdout 0s 8388607KB
stdin
Standard input is empty
stdout
[[1,2,2,3,4,5]]
[]