HASKELL:解决河内塔

2024-06-01

下面的代码解决了 hanoi 使用预定义函数 moveLOD、swapLOI 和 swapLID 返回移动列表的问题。

MoveLOD:将 1 个圆盘从第一个位置移动到三元组第三个位置中的第三个销钉。此外,包含有关运动信息的字符串会堆积在字符串列表中。

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)),[])

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在第一个Pin of the Plate is 'o',您还需要提供当角色是其他角色时的方程。

当接收到的参数与任何有定义方程的模式不匹配时,就会出现“非穷举模式”错误。解决这个问题的唯一方法是提供其余模式的方程。

在您修改后的代码中,首先,您对原始引脚为空的情况的处理不正确,

hanoi (((o,0),i,d),s) = ((('o',0),('i',0),('d',0)),[])

意味着无论何时应用这种情况,结果都是相同的d and i是。什么时候hanoi被调用自chamahanoi当参数大于 2 时,有时原点会变空,并且由于在调用链之上只有hanoi and swapLOI,那个恒定的结果就会冒出来。您会得到正确的结果n == 2 (n == 1直接由第二个方程求解),因为递归调用hanoi那么两者的原极上都只有一个圆盘。

这种情况应该是

hanoi (((o,0),i,d),s) = (((o,0),i,d),s)

这仍然不会产生正确的结果(错误的移动顺序),因为一般情况下的递归是错误的。

You

  • 将顶部圆盘移至中间销(swapLID . moveLOD . swapLID);
  • 然后将剩余的磁盘移动到目的地(hanoi),但这是不允许的,因为最小的圆盘位于中间销上,因此不能将其他圆盘放置在那里;
  • 最后,使用(现在为空)原点销作为中间,将磁盘从中间销移动到目的地。

你应该

  • move n-1从原点到中间销的圆盘,
  • 然后将底部(最大)的磁盘移动到目的地,
  • 最后,移动n-1从中间到目的地的磁盘。

如果没有额外的参数来跟踪要移动的磁盘数量,我看不出有什么简单的方法可以做到这一点。考虑一个四盘游戏。首先,将顶部的三个圆盘移动到中间销,然后将底部的圆盘移动到目标销。现在的任务是使用原始销作为辅助,将三个圆盘从中间销移动到目标销。

正确的做法是顺序

  1. i -> d (([],[1,2,3],[4]) -> ([],[2,3],[1,4]))
  2. i -> o (([],[2,3],[1,4]) -> ([2],[3],[1,4]))
  3. d -> o (([2],[3],[1,4]) -> ([1,2],[3],[4]))
  4. i -> d (([1,2],[3],[4]) -> ([1,2],[],[3,4]))
  5. o -> i (([1,2],[],[3,4]) -> ([2],[1],[3,4]))
  6. o -> d (([2],[1],[3,4]) -> ([],[1],[2,3,4]))
  7. i -> d (([],[1],[2,3,4]) -> ([],[],[1,2,3,4]))

在第 2 步之后,原始目标引脚将成为磁盘(好吧,一个)要移动到的引脚o,但在这种情况下,最低的不得移动。如果唯一的信息是每个引脚上有多少个磁盘以及磁盘应从何处移动到何处,那么如何实现这一点呢?

如果你改变类型hanoi to

hanoi :: Int -> Log -> Log

并称之为

chamahanoi n = hanoi n ((('o',n),('i',0),('d',0)),[])

它很容易实现。

如果您不想这样做,或者不允许这样做,您可以跟踪每个引脚上的大小,并且仅将磁盘移动到较大的引脚上,或者您可以偷偷地在适当的引脚处删除并添加磁盘以进行模拟这种限制,但如果没有适当的解释,就很难将其与作弊区分开来。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HASKELL:解决河内塔 的相关文章

随机推荐

  • 使用变量作为启动进程的文件路径参数

    我想运行一个 exe 它可能位于多个位置 runpath servicepackfolder SQLServer2008SP1 KB968369 IA64 ENU exe Start Process FilePath runpath arg
  • 使用 Vala 和 GLib 的正则表达式

    有没有一个函数 比如http php net manual en function preg match all php http php net manual en function preg match all php 使用 GLibh
  • 使用 UIActionSheet 更改视图时工具栏项目消失

    当从 a 启动视图时UIActionSheet按钮 通过导航栏后退按钮返回视图后 工具栏虽然仍然可见 但上面没有任何以前的按钮 自从更新到 iOS 6 以来 这个错误就出现了 并且是在模拟器和仅运行 iOS 6 的设备上测试时发生的 如果我
  • 哪些对齐问题限制了 malloc 创建的内存块的使用?

    我正在用 C 编写一个用于各种数学计算的库 其中一些需要一些 临时 空间 用于中间计算的内存 所需的空间取决于输入的大小 因此不能静态分配 该库通常用于使用相同大小的输入执行相同类型计算的多次迭代 因此我不希望这样做malloc and f
  • 无法在scrollView中滚动

    我有一个屏幕 我可以在输入字段中输入内容并获得相应的搜索结果 该列表在 ScrollView 中呈现 但当键盘打开时 在 Android 中 它仍然不允许我滚动 我怎样才能解决这个问题 return lt gt addressesFound
  • 如何在 codenameone 中使用两个侧边菜单?

    我想在左侧和右侧添加侧菜单 如何在 codenameone 中完成 getToolbar addCommandToSideMenu new Command 菜单 1 我可以使用上面的代码来添加左侧菜单 我也想在右侧添加它 The Toolb
  • 如何在 RestKit 中为同一类提供两条发布路线

    由于我无法弄清楚如何为同一个类设置两个不同的 POST 资源路径 因此我尝试手动创建 RKObjectLoader 请求 但它似乎不断发送 GET 请求而不是 POST 即使我已将方法设置为邮政 这是我的代码 User user User
  • 如何删除敏感权限以允许应用程序更新 Google Play 控制台

    几个月来 我尝试更新一个应用程序 问题是我想使用短信权限 为此 我必须在 Google Play 控制台中填写敏感权限表格 这样做之后 我的应用程序被拒绝了 很快 我决定让我的应用程序项目走一条不同的路线 我不再需要短信功能了 I have
  • 如何检查DBContext是否已释放?

    我想与从外部 继承类 调用的另一个方法共享数据库上下文 而不创建新的上下文 除非正在释放它 我想检查上下文是否已处理 以便我可以创建新的上下文 这是休息 api 有多个实体的批量上传 我想共享事务 因此如果一个实体失败 它将不会提交到数据库
  • 将 Mongodb 与 Android 应用程序连接

    我正在尝试构建 Android 应用程序来连接到 MongoDB 一直被这个问题困扰 MongoDB 是可访问的 但没有安全性 可以通过手机使用 Mono Explorer 添加数据 public void sendMessage View
  • 将包含特殊字符的标签发送到 Azure 通知中心

    我们想在 iPad 应用程序中使用 Azure 通知中心 但遇到了问题 确定谁收到推送消息的标签是电子邮件地址 如果它仅包含普通字符 则可以正常工作 但当我们尝试发送如下所示的标签时 它不起作用 电子邮件受保护 cdn cgi l emai
  • 使用 gdb 调试 qemu

    如何使用 gdb 调试 qemu 我一直在谷歌搜索但找不到任何具体的东西 我在 GDB 7 5 中遇到错误 gt 访问内存地址时出错 似乎 位置独立可执行文件 有问题 所以使用 configure enable debug disable
  • 为什么我的 AlarmManager 会立即触发?

    我正在尝试构建一个警报应用程序 我之前让闹钟工作过 我可以设置不同的时间 闹钟就会适当地响起 然后我将 ChangeAlarmActivity 的布局更改为 TableLayout 现在它不起作用 我没有碰代码 以下是我设置闹钟的方法 In
  • 如何清除chrome性能条目或绕过其数量限制?

    我使用 Google Chrome 来分析一些使用 Javascript 动态加载脚本和其他资源的网页的性能 我用performance getEntries 方法 但我注意到 Chrome 只记录前 150 个资源 我找不到任何方法来获取
  • 如何使用 javascript 触发表单验证的本机验证气泡/工具提示?

    我有一个附加了 html5 验证 必需 等 属性的表单 有没有一种方法可以触发本机验证气泡 工具提示的出现 而无需模拟表单的提交按钮上的 单击 正如评论中所述 您可以使用 reportValidity 方法 这是广泛支持 https dev
  • 在 Google 地图片段中扩充 XML 时出错

    尝试使用片段显示谷歌地图 使用了以下内容page https developers google com maps documentation android start作为教程 我收到异常 错误膨胀类片段 1 导入jar google p
  • 为什么Eclipse不需要我配置JDK?

    我最近将 Eclipse 下载到 Windows 7 计算机上 该机器已经有 JRE 但我注意到它没有 JDK 我担心我必须下载 JDK 然后将 Eclipse 连接到它 当我能够在 Eclipse 中直接进行编码 编译和运行时 我感到 愉
  • 获取文件夹及其子文件夹中最长文件路径的长度

    我正在寻找一个可以从命令行 批处理 PowerShell 运行的脚本 该脚本将遍历文件夹及其子文件夹 并返回一个数字 该数字是最长文件路径的长度 我已经看到了一些批处理和 PowerShell 脚本 例如 如何在 Windows 中查找路径
  • grep 查找 Unix 中的特殊字符

    我有一个日志文件 application log 其中可能包含以下多行普通和特殊字符字符串 Q 我想搜索包含这个特殊字符串的行号 grep Q application log 上述命令不返回任何结果 获取行号的正确语法是什么 Tell gr
  • HASKELL:解决河内塔

    下面的代码解决了 hanoi 使用预定义函数 moveLOD swapLOI 和 swapLID 返回移动列表的问题 MoveLOD 将 1 个圆盘从第一个位置移动到三元组第三个位置中的第三个销钉 此外 包含有关运动信息的字符串会堆积在字符