Algorithm Haskell中的动态规划记忆
这是我第一次尝试使用(据我所知)动态规划。我试图解决这个有趣的问题:Algorithm Haskell中的动态规划记忆,algorithm,haskell,Algorithm,Haskell,这是我第一次尝试使用(据我所知)动态规划。我试图解决这个有趣的问题: q函数尝试向后递归,跟踪模具的方向(visted从技术上讲是下一个单元,但就递归而言是“visted”,以防止无限的来回循环)。尽管我不确定它提供的答案是否是最好的解决方案,但它似乎确实提供了答案 我希望能想到如何实现某种形式的记忆来加速它——我试图用查找而不是来实现类似记忆化\u fib(参见)的东西,但没有成功,将q映射到(i,j)的组合列表,但没有得到任何内容,没有双关语 哈斯克尔代码: import Data.List
q
函数尝试向后递归,跟踪模具的方向(visted
从技术上讲是下一个单元,但就递归而言是“visted”,以防止无限的来回循环)。尽管我不确定它提供的答案是否是最好的解决方案,但它似乎确实提供了答案
我希望能想到如何实现某种形式的记忆来加速它——我试图用查找而不是来实现类似记忆化\u fib
(参见)的东西,但没有成功
,将q
映射到(i,j)
的组合列表,但没有得到任何内容,没有双关语
哈斯克尔代码:
import Data.List (minimumBy)
import Data.Ord (comparing)
fst3 (a,b,c) = a
rollDie die@[left,right,top,bottom,front,back] move
| move == "U" = [left,right,front,back,bottom,top]
| move == "D" = [left,right,back,front,top,bottom]
| move == "L" = [top,bottom,right,left,front,back]
| move == "R" = [bottom,top,left,right,front,back]
dieTop die = die!!2
leftBorder = max 0 (min startColumn endColumn - 1)
rightBorder = min columns (max startColumn endColumn + 1)
topBorder = endRow
bottomBorder = startRow
infinity = 6*rows*columns
rows = 10
columns = 10
startRow = 1
startColumn = 1
endRow = 6
endColumn = 6
dieStartingOrientation = [4,3,1,6,2,5] --left,right,top,bottom,front,back
q i j visited
| i < bottomBorder || i > topBorder
|| j < leftBorder || j > rightBorder = (infinity,[1..6],[])
| i == startRow && j == startColumn = (dieTop dieStartingOrientation,dieStartingOrientation,[])
| otherwise = (pathCost + dieTop newDieState,newDieState,move:moves)
where previous
| visited == (i, j-1) = zip [q i (j+1) (i,j),q (i-1) j (i,j)] ["L","U"]
| visited == (i, j+1) = zip [q i (j-1) (i,j),q (i-1) j (i,j)] ["R","U"]
| otherwise = zip [q i (j-1) (i,j),q i (j+1) (i,j),q (i-1) j (i,j)] ["R","L","U"]
((pathCost,dieState,moves),move) = minimumBy (comparing (fst3 . fst)) previous
newDieState = rollDie dieState move
main = putStrLn (show $ q endRow endColumn (endRow,endColumn))
导入数据列表(minimumBy)
导入数据。Ord(比较)
fst3(a,b,c)=a
rollDie die@[左、右、上、下、前、后]移动
|移动==“U”=[左、右、前、后、下、上]
|移动==“D”=[左、右、后、前、上、下]
|移动==“L”=[上、下、右、左、前、后]
|移动==“R”=[底部、顶部、左侧、右侧、前部、后部]
dieTop die=die!!2.
leftBorder=最大值0(最小开始列结束列-1)
rightBorder=最小列数(最大开始列数+结束列数+1)
topBorder=endRow
bottomBorder=startRow
无穷大=6*行*列
行=10
列=10
startRow=1
startColumn=1
endRow=6
endColumn=6
模具开始方向=[4,3,1,6,2,5]--左、右、上、下、前、后
q i j访问
|itopBorder
||jrighborder=(无穷大,[1..6],)
|i==startRow&&j==startColumn=(dieTop dieStartingOrientation,dieStartingOrientation,[]))
|否则=(pathCost+dieTop-newDieState,newDieState,move:moves)
以前在哪里
|到访==(i,j-1)=zip[qi(j+1)(i,j),q(i-1)j(i,j)][“L”,“U”]
|到访==(i,j+1)=zip[qi(j-1)(i,j),q(i-1)j(i,j)][“R”,“U”]
|否则=zip[qi(j-1)(i,j),qi(j+1)(i,j),q(i-1)j(i,j)][“R”,“L”,“U”]
((路径成本,死亡状态,移动),移动)=最小值(比较(fst3.fst))上一个
newDieState=滚动Die dieState移动
main=putStrLn(显示$q endRow endColumn(endRow,endColumn))
我解决此类问题的工具是库
要使用它,只需导入数据.memobombinators
,将q
重命名为其他名称,例如q'
(但保持递归调用不变),然后定义一个新的q
,如下所示:
q = M.memo3 M.integral M.integral (M.pair M.integral M.integral) q'
memo3
为一个三参数函数创建一个备忘录,为每个参数指定备忘录
integral
是一个简单的整数类型记忆工具
pair
组合两个记忆器,为这些类型的成对记忆器创建一个记忆器
- 最后,我们将此记忆器应用于
q'
,以获得一个记忆版本
就这样。您的函数现在已被记忆。测试时间:
> :set +s
> q endRow endColumn (endRow,endColumn)
(35,[5,2,4,3,6,1],["R","R","R","R","R","U","U","U","U","U"])
(0.01 secs, 516984 bytes)
完整代码如下:
导入数据列表(minimumBy)
导入数据。Ord(比较)
导入符合条件的数据.M作为M
fst3(a,b,c)=a
rollDie die@[左、右、上、下、前、后]移动
|移动==“U”=[左、右、前、后、下、上]
|移动==“D”=[左、右、后、前、上、下]
|移动==“L”=[上、下、右、左、前、后]
|移动==“R”=[底部、顶部、左侧、右侧、前部、后部]
dieTop die=die!!2.
leftBorder=最大值0(最小开始列结束列-1)
rightBorder=最小列数(最大开始列数+结束列数+1)
topBorder=endRow
bottomBorder=startRow
无穷大=6*行*列
行=10
列=10
startRow=1
startColumn=1
endRow=6
endColumn=6
模具开始方向=[4,3,1,6,2,5]--左、右、上、下、前、后
q=M.3 M.积分M.积分(M.对M.积分M.积分)q'
哪里
q'i'j访问
|itopBorder | | jrighborder=(无穷大,[1..6],)
|i==startRow&&j==startColumn=(dieTop dieStartingOrientation,dieStartingOrientation,[]))
|否则=(pathCost+dieTop-newDieState,newDieState,move:moves)
以前在哪里
|到访==(i,j-1)=zip[qi(j+1)(i,j),q(i-1)j(i,j)][“L”,“U”]
|到访==(i,j+1)=zip[qi(j-1)(i,j),q(i-1)j(i,j)][“R”,“U”]
|否则=zip[qi(j-1)(i,j),qi(j+1)(i,j),q(i-1)j(i,j)][“R”,“L”,“U”]
((路径成本,死亡状态,移动),移动)=最小值(比较(fst3.fst))上一个
newDieState=滚动Die dieState移动
main=putStrLn(显示$q endRow endColumn(endRow,endColumn))
我想如果你发布了你的尝试,但没有成功,那会有所帮助。我很久以前在Haskell花了很多时间来思考回忆录的问题。我记不起细节,但最终我成功了(我想,它可能还有其他问题,比如空间泄漏),定义了一个数组实例,以便根据其他数组元素计算任何给定索引的值。然后,懒惰的评估似乎迫使所有数组元素按正确的顺序“填充”,这似乎有点不可思议(尽管我感到欣慰而不是高兴)。在数据结构“leads”下,函数“follow”。@j_random_hacker请检查应用的骰子算法——2.13秒内300x300,没有表格,并且比Paul的a*小,酷还是什么?谢谢我用这个包做了实验,但不知道如何解释我的q函数类型。
import Data.List (minimumBy)
import Data.Ord (comparing)
import qualified Data.MemoCombinators as M
fst3 (a,b,c) = a
rollDie die@[left,right,top,bottom,front,back] move
| move == "U" = [left,right,front,back,bottom,top]
| move == "D" = [left,right,back,front,top,bottom]
| move == "L" = [top,bottom,right,left,front,back]
| move == "R" = [bottom,top,left,right,front,back]
dieTop die = die!!2
leftBorder = max 0 (min startColumn endColumn - 1)
rightBorder = min columns (max startColumn endColumn + 1)
topBorder = endRow
bottomBorder = startRow
infinity = 6*rows*columns
rows = 10
columns = 10
startRow = 1
startColumn = 1
endRow = 6
endColumn = 6
dieStartingOrientation = [4,3,1,6,2,5] --left,right,top,bottom,front,back
q = M.memo3 M.integral M.integral (M.pair M.integral M.integral) q'
where
q' i j visited
| i < bottomBorder || i > topBorder || j < leftBorder || j > rightBorder = (infinity,[1..6],[])
| i == startRow && j == startColumn = (dieTop dieStartingOrientation,dieStartingOrientation,[])
| otherwise = (pathCost + dieTop newDieState,newDieState,move:moves)
where previous
| visited == (i, j-1) = zip [q i (j+1) (i,j),q (i-1) j (i,j)] ["L","U"]
| visited == (i, j+1) = zip [q i (j-1) (i,j),q (i-1) j (i,j)] ["R","U"]
| otherwise = zip [q i (j-1) (i,j),q i (j+1) (i,j),q (i-1) j (i,j)] ["R","L","U"]
((pathCost,dieState,moves),move) = minimumBy (comparing (fst3 . fst)) previous
newDieState = rollDie dieState move
main = putStrLn (show $ q endRow endColumn (endRow,endColumn))