Haskell 解决狮子、狼和山羊的问题
我正在努力解决狮子、狼和山羊的问题 这就是我的解决方案:Haskell 解决狮子、狼和山羊的问题,haskell,Haskell,我正在努力解决狮子、狼和山羊的问题 这就是我的解决方案: eat :: (Int, Int, Int) -> (Int, Int, Int) eat (lions, wolves, goats) = eat (lions - 1, wolves - 1, goats - 1) eat (0, wolves, goats) = eat (1, wolves - 1, goats - 1) eat (lions, 0, goats) = eat (lions - 1, 1, goats - 1
eat :: (Int, Int, Int) -> (Int, Int, Int)
eat (lions, wolves, goats) = eat (lions - 1, wolves - 1, goats - 1)
eat (0, wolves, goats) = eat (1, wolves - 1, goats - 1)
eat (lions, 0, goats) = eat (lions - 1, 1, goats - 1)
eat (lions, wolves, 0) = eat (lions - 1, wolves - 1, 1)
eat (0, 0, goats) = (0, 0, goats)
此代码可以编译,但代码永远挂起。我很确定我错过了一场比赛,但我不知道是什么。请告诉我如何正确解决此问题。模式是自上而下、从左到右读取的。因此,您的第一个模式匹配所有其他模式。重新排序:
eat :: (Int, Int, Int) -> (Int, Int, Int)
eat (0 , 0 , goats) = (0 , 0 , goats )
eat (0 , wolves , goats) = eat (1 , wolves - 1 , goats - 1)
eat (lions , 0 , goats) = eat (lions - 1 , 1 , goats - 1)
eat (lions , wolves , 0) = eat (lions - 1 , wolves - 1 , 1 )
eat (lions , wolves , goats) = eat (lions - 1 , wolves - 1 , goats - 1)
请注意,这假设所有值最初都为正值。如果其中一个是负数,您仍然会得到循环。还要注意的是,你错过了其他的“稳定”状态,你对于狮子、狼和山羊的非零群的逻辑是错误的。如果有山羊和狼,狮子可能会吃掉它们中的任何一只。此外,狼可能比狮子先吃山羊
这就是非决定论将发挥作用的部分。这里有一个解决方案,可行,但没有整理,因为实现了我想到的第一件事。我相信这是可以改进的 让我们将要跟踪的状态定义为(狮子、狼、山羊) 饮食规则如下所示
lw,lg,wg :: State -> State
lw (n,w,g) = (n-1,w-1,g+1)
lg (n,w,g) = (n-1,w+1,g-1)
wg (n,w,g) = (n+1,w-1,g-1)
由于每一步的步数都会呈指数增长,因此最好删除冗余状态和不允许的状态(负值),定义辅助函数
nonnegative:: State -> Bool
nonnegative (n,w,g) = n>=0 && w>=0 && g>=0
程序的核心是步进函数,在这里我们将规则应用于当前状态
step :: S.Set State -> S.Set State
step s = S.unions [mapfilter lg s, mapfilter lw s, mapfilter wg s]
此处唯一性外包给数据。使用带S前缀的限定项进行设置,需要导入
import qualified Data.Set as S (Set,toList,unions,singleton,map,filter,null)
mapfilter正在应用进食规则并过滤非负项
mapfilter f s = S.filter nonnegative $ S.map f s
我们将计算步骤,直到找到解决方案
solution :: S.Set State -> State
solution s | S.null final = solution $ step s
| otherwise = result s
where final = S.filter done s
其中状态的两个元素为零
done (n,w,g) | n==0 = w==0 || g==0
| w==0 = g==0
| otherwise = False
并从集合中检索第一个结果
result :: S.Set State -> State
result s = head $ Prelude.filter done $ S.toList s
使用链接中引用的初始值
initial :: S.Set State
initial = S.singleton (6,55,17)
当我们以初始状态运行时,就会得到结果
Prelude> solution initial
(23,0,0)
那是23只狮子
更新
我稍微清理了代码,仍然返回找到的第一个解决方案
import Data.Set (Set,toList,singleton,map,filter,null,union,empty)
type State = (Int, Int, Int) -- lions, wolfs, goats
lw,lg,wg :: State -> State
lw (n,w,g) = (n-1,w-1,g+1)
lg (n,w,g) = (n-1,w+1,g-1)
wg (n,w,g) = (n+1,w-1,g-1)
done,nonnegative :: State -> Bool
done (n,w,g) | n==0 = w==0 || g==0
| w==0 = g==0
| otherwise = False
nonnegative (n,w,g) = n>=0 && w>=0 && g>=0
step :: Set State -> Set State
step s = mapfilters [lg,lw,wg] s
mapfilters :: [State -> State] -> Set State -> Set State
mapfilters [] s = empty
mapfilters (f:fs) s = union (mf f s) (mapfilters fs s)
where mf f s = Data.Set.filter nonnegative $ Data.Set.map f s
solution :: Set State -> Set State
solution s | Data.Set.null final = solution (step s)
| otherwise = final
where final = Data.Set.filter done s
run = head $ toList $ solution $ singleton (6,55,17)
有效地做到这一点的一个关键是要认识到问题看起来只是不对称的。在每个步骤中,有三种可能性:
g
、l
和w
。所以我们需要平衡动作来平衡狮子和狼。我们还需要(l+w)/2个动作来杀死狮子和狼。因此,最终山羊的总数是g-| l-w |/2+(l+w)/2
。因此
如果狮子比狼多,最后会有山羊
如果狼比狮子多,最后就会有山羊
现在,您可以在固定时间内计算最终配置,并且可以在线性时间内计算到达该配置的路径。对于GHC 7.10.3,编译器会给出一个非常有用的警告,这恰好是问题的原因。它试图帮助你,不要忽视它!您有重叠的模式,如果您启用了它们,警告会告诉您。事实上,第一个方程式涵盖了任何输入三元组,因此最后一个方程式永远不会被使用,从而导致无限循环。此外,这个问题似乎比上面的代码所暗示的要复杂得多:它涉及一个不确定的过渡系统,我们需要计算它的所有最终状态。我们基本上需要做一个图形访问。注意这似乎是错误的吃(狮子,狼,山羊)=吃(狮子-1,狼-1,山羊-1)
谁把它们都吃了?在这种状态下,您应该有三种不同的替代结果。你也没有其他终端状态可以只留下狮子和狼。对于非决定论,请查找列表单子。@PyRulez:如果你只使用列表单子,速度会非常慢。备注:不一定只有一个解决方案。如果你从(1,1,1)开始,你可以得到(2,0,0)(狼吃山羊),(0,2,0)(
Prelude> solution initial
(23,0,0)
import Data.Set (Set,toList,singleton,map,filter,null,union,empty)
type State = (Int, Int, Int) -- lions, wolfs, goats
lw,lg,wg :: State -> State
lw (n,w,g) = (n-1,w-1,g+1)
lg (n,w,g) = (n-1,w+1,g-1)
wg (n,w,g) = (n+1,w-1,g-1)
done,nonnegative :: State -> Bool
done (n,w,g) | n==0 = w==0 || g==0
| w==0 = g==0
| otherwise = False
nonnegative (n,w,g) = n>=0 && w>=0 && g>=0
step :: Set State -> Set State
step s = mapfilters [lg,lw,wg] s
mapfilters :: [State -> State] -> Set State -> Set State
mapfilters [] s = empty
mapfilters (f:fs) s = union (mf f s) (mapfilters fs s)
where mf f s = Data.Set.filter nonnegative $ Data.Set.map f s
solution :: Set State -> Set State
solution s | Data.Set.null final = solution (step s)
| otherwise = final
where final = Data.Set.filter done s
run = head $ toList $ solution $ singleton (6,55,17)