在哈斯克尔回溯

时间:2010-04-12 16:06:43

标签: haskell backtracking

我必须遍历一个矩阵,并说明每种类型有多少“特征区域”。

特征区域被定义为值为n或> n的元素相邻的区域。

例如,给定矩阵:

0 1 2 2
0 1 1 2
0 3 0 0

类型1的单个特征区域等于原始矩阵:

0 1 2 2
0 1 1 2
0 3 0 0

类型2有两个特征区域:

0 0 2 2    0 0 0 0
0 0 0 2    0 0 0 0
0 0 0 0    0 3 0 0

类型3的一个特征区域:

0 0 0 0 
0 0 0 0
0 3 0 0 

因此,对于函数调用:

countAreas [[0,1,2,2],[0,1,1,2],[0,3,0,0]] 

结果应为

[1,2,1]

我还没有定义countAreas,当我的visit函数没有更多可能的方格移动它被卡住并且没有进行正确的递归调用时,我就停留了。我是函数式编程的新手,我仍然在思考如何在这里实现回溯算法。看看我的代码,我该怎么做才能改变它?

move_right :: (Int,Int) -> [[Int]] -> Int -> Bool
move_right (i,j) mat cond | (j + 1) < number_of_columns mat && consult (i,j+1) mat /= cond = True
               | otherwise = False

move_left :: (Int,Int) -> [[Int]] -> Int -> Bool
move_left (i,j) mat cond | (j - 1) >= 0 && consult (i,j-1) mat /= cond = True
               | otherwise = False

move_up :: (Int,Int) -> [[Int]] -> Int -> Bool
move_up (i,j) mat cond | (i - 1) >= 0 && consult (i-1,j) mat /= cond = True
               | otherwise = False

move_down :: (Int,Int) -> [[Int]] -> Int -> Bool
move_down (i,j) mat cond | (i + 1) < number_of_rows mat && consult (i+1,j) mat /= cond = True
               | otherwise = False

imp :: (Int,Int) -> Int
imp (i,j) = i


number_of_rows :: [[Int]] -> Int
number_of_rows i = length i

number_of_columns :: [[Int]] -> Int
number_of_columns (x:xs) =  length x

consult :: (Int,Int) -> [[Int]] -> Int
consult (i,j) l = (l !! i) !! j

visited :: (Int,Int) -> [(Int,Int)] -> Bool
visited x y = elem x y

add :: (Int,Int) -> [(Int,Int)] -> [(Int,Int)]
add x y = x:y

visit :: (Int,Int) -> [(Int,Int)] -> [[Int]] -> Int -> [(Int,Int)]
visit (i,j) vis mat cond | move_right (i,j) mat cond && not (visited (i,j+1) vis) = visit (i,j+1) (add (i,j+1) vis) mat cond
               | move_down (i,j) mat cond && not (visited (i+1,j) vis) = visit (i+1,j) (add (i+1,j) vis) mat cond
               | move_left (i,j) mat cond && not (visited (i,j-1) vis) = visit (i,j-1) (add (i,j-1) vis) mat cond
               | move_up (i,j) mat cond && not (visited (i-1,j) vis) = visit (i-1,j) (add (i-1,j) vis) mat cond
               | otherwise = vis

2 个答案:

答案 0 :(得分:3)

这会帮助你在这里使用数组类型,而不是列表列表吗?您仍在使用更好的数据结构进行函数式编程。

如果适合您,您可以创建Array (Int,Int) Int。参见:

http://hackage.haskell.org/packages/archive/array/0.2.0.0/doc/html/Data-Array-IArray.html

import Data.Array

...获取图书馆。

答案 1 :(得分:1)

我认为回溯实际上并不是你所追求的。在我看来,你的目标是让你的visit函数建立一个访问列表,因为它从符合某些条件的某个点找到矩阵中的所有连通元素。您需要考虑的是什么算法将实现这一目标。不要担心在功能或命令式编程方面表达它(尚未)。试想一下:算法本质上是递归的吗?迭代?如果你在计算过程中停止了它,你怎么知道算法中接下来要做什么?你需要什么数据?

我现在不担心代码的各种改进(使用Array或删除if语句等等),您可以稍后再进行修改。你缺少的关键是一个可行的算法。