在Haskell。
我写了一个函数给出了一个难题的状态,就像人们还没有交叉,那些已经交叉的人,给出了从一侧到另一侧的所有可能移动的列表(移动两个人前进和一个倒退的人。)
module DarkBridgeDT where
data Crossing = Trip [Float] [Float] Float deriving (Show)
data RoundTrip = BigTrip Crossing Crossing deriving (Show)
trip :: [Float] -> [Float] -> Float -> Crossing
trip x y z = Trip x y z
roundtrip :: Crossing -> Crossing -> RoundTrip
roundtrip x y = BigTrip x y
next :: Crossing -> [RoundTrip]
next (Trip [] _ _) = []
next (Trip (a:b:[]) s _ )
|a>b = [BigTrip (Trip [] (a:b:s) a) (Trip [] [] 0)]
|otherwise = [BigTrip (Trip [] (b:a:s) b) (Trip [] [] 0)]
next (Trip d s _) = [BigTrip (Trip [x,z] (i:j:s) j) b | i <- d, j <- d, i < j, x <- d, z <- d, x < z, z /= i, z /= j, x /= z, x /= i, x /= j, b <- (back [x,z] (i:j:s))]
where
back [] s = []
back d s = [Trip (i:d) (filter (/= i) s) i | i <- s]
现在我需要一个函数,它给出一个上面的状态,并且最大时间量会在不到给定时间内给出谜题的所有可能解决方案。
我所拥有的就是:
cross :: Crossing -> Float -> [[RoundTrip]]
cross (Trip [] _ _) _ = []
cross (Trip _ _ acu) max
| acu > max = []
cross (Trip a b acu) max = map (cross (map (crec) (next (Trip a b acu)) acu)) max
where
crec (BigTrip (Trip _ _ t1) (Trip a b t2)) acu = (Trip a b (t1+t2+acu))
当然不能编译,第5行是让我疯狂的那一行。有什么输入吗?
编辑:
cross
函数用于将next
函数应用于调用的最后一个next
函数的每个结果。
如果next的第一个结果类似于:[A,B,C,D]
那么它会在ABC和D上调用next
以查看是否有任何或所有这些结果都是在max
以内找到解决方案(ABC和D将是Crossings里面包含浮动的,这些浮动是广告的时间并与max进行比较。
我的数据结构是
交叉:包含桥梁的第一面(人们用它们穿过桥梁所代表的时间)桥梁的另一边(与另一边相同)和一个代表最大时间的时间最后越过桥梁(在第一个十字路口中最大的两个或在第二个十字路口中唯一的一个)或跨越桥梁的时间量(在十字功能中)。
RoundTrip:代表两个交叉点,第一个和第二个交叉点,一个到达安全点,另一个到达危险点。
cross (Trip [1,2,5,10] [] 0) 16
应该给出一个空列表,因为没有解决方案需要不到17分钟(或任何时间单位)。
cross (Trip [1,2,5,10] [] 0) 17
应该将拼图的正常解决方案作为往返列表。
我希望这更清楚。
EDIT2: 我终于明白了。在我完成我之前,我阅读了Carsten的解决方案,我们几乎完全相同。他使用了更高级的语法和更复杂的结构,但它非常相似:
module DarkBridgeST where
data Torch = Danger | Safety deriving (Eq,Show)
data State = State
[Float] -- people in danger
[Float] -- people safe
Torch -- torch position
Float -- remaining time
deriving (Show)
type Crossing = [Float]
classic :: State
classic = State [1,2,5,10] [] Danger 17
next :: State -> [Crossing] -- List all possible moves
next (State [] _ _ _) = [] -- Finished
next (State _ [] Safety _) = [] -- No one can come back
next (State danger _ Danger rem) = [[a,b] | a <- danger, b <- danger, a /= b, a < b, max a b <= rem]
next (State _ safe Safety rem) = [[a] | a <- safe, a <= rem]
cross :: State -> Crossing -> State -- Crosses the bridge depending on where the torch is
cross (State danger safe Danger rem) cross = State (taking cross danger) (safe ++ cross) Safety (rem - (maximum cross))
cross (State danger safe Safety rem) cross = State (danger ++ cross) (taking cross safe) Danger (rem - (maximum cross))
taking :: [Float] -> [Float] -> [Float]
taking [] d = d
taking (x:xs) d = taking xs (filter (/=x) d)
solve :: State -> [[Crossing]]
solve (State [] _ _ _) = [[]]
solve sf = do
c <- next sf
let sn = cross sf c
r <- solve sn
return (c:r)
总而言之,感谢所有人。我是Haskell编程的新手,这帮助我理解了很多东西。我希望这篇文章也可以帮助有人像我一样开始像我这样的人:)
答案 0 :(得分:2)
我不会在这里保留大部分代码。
第一个问题是数据结构。 Crossing
实际上并不代表与过桥相关的任何事情,而是在过桥之前或之后的状态。并且您不能使用RoundTrip
因为桥接交叉的数量总是奇数。
我正在重命名我实际保留的数据结构,但我没有保持不变。
data Bank = Danger | Safety deriving (Eq,Show)
data PuzzleState = PuzzleState
[Float] -- people still in danger
[Float] -- people on the safe bank
Bank -- current location of the torch
Float -- remaining time
type Crossing = ([Float],Bank)
修改/编写这些功能留给读者练习
next :: PuzzleState -> [Crossing] -- Create a list of possible crossings
applyCrossing :: PuzzleState -> Crossing -> PuzzleState -- Create the next state
然后像这个函数可以把它们放在一起(如果剩余时间太短,假设next
返回一个空列表):
cross (PuzzleState [] _ _ _) = [[]]
cross s1 = do
c <- next s1
let s2 = applyCrossing s1 c
r <- cross s2
return $ c : r
答案 1 :(得分:0)
只是为了好玩,使用懒树的方法:
.helper{
display:inline-block;
height:100%;
vertical-align:middle;
}
/*container*/
.metd{
vertical-align:middle;
display:inline-block;
}
然后你可以得到一份解决方案清单:
import Data.List
import Data.Tree
type Pawn = (Char, Int)
data Direction = F | B
data Turn = Turn {
_start :: [Pawn],
_end :: [Pawn],
_dir :: Direction,
_total :: Int
}
type Solution = ([String], Int)
-- generate a tree
mkTree :: [Pawn] -> Tree Turn
mkTree p = Node{ rootLabel = s, subForest = branches s }
where s = Turn p [] F 0
-- generates a node for a Turn
mkNode :: Turn -> Tree Turn
mkNode t = Node{ rootLabel = t, subForest = branches t }
-- next possible moves
branches :: Turn -> [Tree Turn]
-- complete
branches (Turn [] e d t) = []
-- moving forward
branches (Turn s e F t) = map (mkNode.turn) (next s)
where
turn n = Turn (s\\n) (e++n) B (t+time n)
time = maximum . map snd
next xs = [x| x <- mapM (const xs) [1..2], head x < head (tail x)]
-- moving backward
branches (Turn s e B t) = map (mkNode.turn) e
where
turn n = Turn (n:s) (delete n e) F (t+time n)
time (_,b) = b
solve :: Int -> Tree Turn -> [Solution]
solve limit tree = solve' [] [] limit tree
where
solve' :: [Solution] -> [String] -> Int -> Tree Turn -> [Solution]
solve' sols cur limit (Node (Turn s e d t) f)
| and [t <= limit, s == []] = sols ++ [(cur++[step],t)]
| t <= limit = concat $ map (solve' sols (cur++[step]) limit) f
| otherwise = []
where step = "[" ++ (v s) ++ "|" ++ (v e) ++ "]"
v = map fst
或者还生成一个解决方案树:
solve 16 $ mkTree [('a',2), ('b',4), ('c',8)]
=> [(["[abc|]","[c|ab]","[ac|b]","[|bac]"],14),(["[abc|]","[c|ab]","[bc|a]","[|abc]"],16),(["[abc|]","[b|ac]","[ab|c]","[|cab]"],14),(["[abc|]","[a|bc]","[ba|c]","[|cab]"],16)]
然后:
draw :: Int -> Tree Turn -> Tree String
draw limit (Node (Turn s e d t) f)
| t > limit = Node "Time Out" []
| s == [] = Node ("Complete: " ++ step) []
| otherwise = Node step (map (draw limit) f)
where step = "[" ++ (v s) ++ "|" ++ (v e) ++ "]" ++ " - " ++ (show t)
v = map fst
将导致:
putStrLn $ drawTree $ draw 16 $ mkTree [('a',2), ('b',4), ('c',8)]