一个功能,旅程,它以行程开始的城市名称和城市名称结束,并返回一个变化最少的旅程。例如,仅考虑曼谷航空公司,
journey "Singapore" "Singapore"
and returns[ ]
journey "Singapore" "Bangkok"
and returns [ ("Singapore", "Bangkok Airways", "Bangkok") ]
journey "Singapore" "New Delhi"
and returns [ ("Singapore", "Bangkok Airways", "New Delhi") ]
在更大的网络中,
journey "Singapore" "France"
====> [ ("Singapore", "Bangkok Airways", "Greece") ,("Greece", "Lufthansa", "France")]
这是我到目前为止所拥有的
city :: String -> (String,String,String)
city "Singapore" =("Singapore","Bangkok Airways", "Bangkok")
city "Bangkok" =("Bangkok","Bangkok Airways", "Bago")
city "Bago" = ("Bago", "Bangkok Airways", "Yangon")
city "Yangon" =("Yangon", "Bangkok Airways", "New Delhi")
city "New Delhi" = ("New Delhi", "Bangkok Airways", "Kiev")
然而,这将返回旅程,并不意味着它是最短的。
还有城市的定义,它需要更多的抛光,因为我不认为它是有效的。
答案 0 :(得分:4)
您可以使用名为"结扎"的技巧。使用此技术,图形表示为无限树:
data Rose a = Rose a [Rose a]
data Graph a = Graph [(a, Rose a)]
主要功能很简单:
lookupRose :: Eq a => a -> Graph a -> Rose a
lookupRose i (Graph rs) = fromJust $ lookup i rs
path :: Eq a => a -> a -> Graph a -> [a]
path orig dest gr = path' (lookupRose orig gr) where
path' (Rose p ps)
| p == dest = [p]
| otherwise = p : foldr1 shortest (map path' ps)
我假设,图中没有没有邻居的节点。所以有两种情况:
请注意,没有循环检测,但添加它很容易。
shortest
函数与图形无关,它只接收两个列表并返回最短的:
shortest :: [a] -> [a] -> [a]
shortest xs ys = snd $ shortest' xs ys where
shortest' [] ys = (True, [])
shortest' xs [] = (False, [])
shortest' (x:xs) (y:ys) = case shortest' xs ys of
~(b, zs) -> (b, (if b then x else y):zs)
我们需要一个从列表中构建图形的函数:
fromList :: Eq a => [(a, [a])] -> Graph a
fromList xs = graph where
graph = Graph $ map irose xs
irose (i, is) = (i, Rose i $ map (\i -> lookupRose i graph) is)
这就是全部。例如:http://ideone.com/9le557
修改强>
shortest
函数的实现是懒惰的,因此即使shortest xs ys
和z1 : z2 : ...
无限,xs
也会生成ys
形式的列表。因此,length $ take 10 $ shortest [1..] [2..]
会返回10
,例如。
我们假设shortest
的定义如下:
shortest :: [a] -> [a] -> [a]
shortest xs ys = either id id $ shortest' xs ys where
shortest' [] ys = Left []
shortest' xs [] = Right []
shortest' (x:xs) (y:ys) = either (Left . (x:)) (Right . (y:)) $ shortest' xs ys
然后这个表达
take 5 $ shortest [1..10] [2..]
缩减为[1,2,3,4,5]
。但
take 5 $ shortest [1..10] (shortest [1..] [2..])
导致堆栈溢出。这是因为shortest
要求两个列表都处于弱头正常形式(whnf)(即某些[]
和x:xs
的{{1}}或x
,但
xs
缩减为
shortest [1..] [2..]
不在whnf中。表达式被迫进一步推动:
either (Left . (1:)) (Right . (2:)) $ ...
等等到堆栈溢出。
但是
either (Left . (1:)) (Right . (2:)) $ either (Left . (2:)) (Right . (3:)) $ ...
缩减为
foldr1 shortest (map path' ps)
如果shortest (path' p1) (shortest (path' p2) (path' p3))
。因此ps = [p1, p2, p3]
函数必须是惰性的,因为shortest
和path' p2
在具有周期的图形中可以是无限的。