下面的代码解决了hanoi使用预定义函数moveLOD,swapLOI和swapLID返回移动列表。
MoveLOD:将三张光盘从第一个位置移动到三元组第三个位置的第三个位置。另外,一个包含有关移动信息的字符串正在堆叠在字符串列表上。
type Pin = (Char, Int) -- Represents a rod, named for a character and the number of disks in it.
type Plate = (Pin, Pin, Pin) -- Represents the configuration of the three rods.(Origin,Intermediate,Destination
type Log = (Plate, [String]) -- Represents a state formed by the configuration of rods and a list of strings that will record the movements made by the algorithm.
moveLOD :: Log -> Log
moveLOD (((o,n), i ,(d,k)),s) = (((o,n-1), i ,(d,k+1)), (o:" -> " ++ [d]):s)
-- swapLOI: Change the positions of the origin rods and intermediate rods.
swapLOI:: Log->Log
swapLOI ((o,i,d),s) = ((i,o,d),s)
-- swapoLID : Change the positions of the intermediate rods and destination rods.
swapLID:: Log->Log
swapLID ((o,i,d),s) = ((o,d,i),s)
hanoi :: Log -> Log
hanoi:: Int->Log->[String]
hanoi 1 log = transformaLista(moveLOD log)
hanoi n log = hanoi (n-1) (swapLID log) ++ hanoi 1 log ++ hanoi (n-1) (swapLOI(log))
changeToList::Log->[String]
changeToList(p,s) = s
callHanoi:: Int->[String]
callHanoi n = hanoi n ((('O',n),('I',0),('D',0)),[])
答案 0 :(得分:3)
hanoi :: Log -> Log
hanoi ((('o',0),i,d),s) = ((('o',0),('i',0),('d',0)), [])
hanoi ((('o',1),i,d),s) = moveLOD((('o',1),i,d),s)
hanoi ((('o',n),i,d),s)= hanoi(swapLOI(hanoi(swapLOI(swapLID(moveLOD(swapLID((('o',n),i,d),s)))))))
仅定义Char
的{{1}}中Pin
为Plate
的{{1}}的参数函数,还需要提供角色何时为某事物的方程式其他
当接收到与没有定义方程的任何模式匹配的参数时,引发“非详尽模式”错误。解决这个问题的唯一方法是为其余模式提供方程式。
在修改后的代码中,首先,您对原始引脚为空的情况的处理是不正确的,
'o'
表示无论何种hanoi (((o,0),i,d),s) = ((('o',0),('i',0),('d',0)),[])
和d
,无论何时应用此情况,结果都是相同的。当i
从hanoi
调用且参数大于2时,原点极点会变空,并且从上面开始,调用链中只有chamahanoi
和{{1}那个不变的结果冒出来了。您得到hanoi
的正确结果(swapLOI
由第二个等式直接求解),因为递归调用n == 2
然后两者在原点上只有一个磁盘。
那个案子应该是
n == 1
这仍然不会产生正确的结果(错误的移动序列),因为一般情况下的递归是错误的。
您
hanoi
); hanoi (((o,0),i,d),s) = (((o,0),i,d),s)
),但这是不允许的,因为最小的磁盘位于中间引脚上,因此不能放置其他磁盘; 你应该
swapLID . moveLOD . swapLID
个磁盘从原点移动到中间引脚hanoi
磁盘从中间位置移动到目标位置。如果没有额外的参数来跟踪要移动的磁盘数量,我看不到一种简单的方法。考虑一个四磁盘游戏。首先,将前三个磁盘移动到中间引脚,然后将底部磁盘移动到目标引脚。现在的任务是将三个磁盘从中间引脚移动到目标引脚,使用原始引脚作为帮助。
正确的方法是序列
n-1
(n-1
)i -> d
(([],[1,2,3],[4]) -> ([],[2,3],[1,4])
)i -> o
(([],[2,3],[1,4]) -> ([2],[3],[1,4])
)d -> o
(([2],[3],[1,4]) -> ([1,2],[3],[4])
)i -> d
(([1,2],[3],[4]) -> ([1,2],[],[3,4])
)o -> i
(([1,2],[],[3,4]) -> ([2],[1],[3,4])
)o -> d
(([2],[1],[3,4]) -> ([],[1],[2,3,4])
)在步骤2之后,原始目标引脚成为将磁盘(一个)移动到i -> d
的引脚,但在这种情况下,最低的引脚不会被移动。如果唯一的信息是每个引脚上有多少个磁盘,以及磁盘的移动位置,怎么能实现呢?
如果您将([],[1],[2,3,4]) -> ([],[],[1,2,3,4])
的类型更改为
o
并将其命名为
hanoi
很容易实现。
如果您不想这样做,或者不允许这样做,您可以跟踪每个引脚的大小,只将磁盘移动到较大的磁盘上,或者您可以偷偷地删除并添加适当的磁盘如果没有正确的解释,就很难区分作弊。
答案 1 :(得分:3)
如果它对任何人有帮助,这里是另一个河内算法塔:
hanoi 0 _ _ _ = []
hanoi n a b c = hanoi (n-1) a c b ++ [(a,b)] ++ hanoi (n-1) c b a
例如,hanoi 2“a”“b”“c”== [(“a”,“c”),(“a”,“b”),(“c”,“b”)]