最新消息:

农夫过河——狼羊菜问题

App Inventor 少儿编程 4635浏览 0评论

话说一位农夫带着一只狼、一只羊和一个卷心菜过河,无奈船小,农夫每次只能运送一样东西,考虑到狼吃羊、羊吃菜,因此运送的顺序至关重要。

 

在现实世界里解决这个问题并不困难,相信很多人都已经有了答案,但是如何用程序来解决这一问题,就需要动动脑筋了。

 

这又是一个与移动物品有关的问题,在前面汉诺塔的例子中,我们已经领略了解决这类问题的方法,大致分为三个步骤:

  1. 将现实问题转化为数学问题,即,建立模型;
  2. 将数学问题转化为程序问题,即,给出数据结构及算法;
  3. 编写程序解决问题。

下面我们就沿着这样的思路来寻找问题的答案。

 

一、建立模型

首先考虑如何用数学方法表达狼羊菜之间的关系。最简单的数学元素莫过于自然数,而最简单的运算莫过于自然数的四则运算。我们建立如下对应关系:

  • 狼=1
  • 羊=2
  • 菜=3

那么避免狼吃羊、羊吃菜的问题,就转化为求差值的减法问题,当它们之间差值的绝对值等于1时,会发生“危险”,应该加以避免。

 

二、数据结构及算法

在汉诺塔问题中,我们使用了出发点、落脚点这样的名称,来描述圆盘移动的起点与终点,这里我们也要为移动的起点与终点命名。考虑到河有两个岸,假设农夫从左岸向右岸运送物资,那么将起点命名为左岸,将终点命名为右岸,然后用两个列表分别记录左岸及右岸物品的种类。

 

初始状态下,左岸列表为(1,2,3),即(狼,羊,菜),而右岸列表为空,当运送完成后,左岸列表为空,右岸列表中包含了狼羊菜三项(无需考虑顺序)。这就是我们解决这一问题所采用的数据结构。

 

接下来考虑如何实现两个状态之间的转化。首先从左岸移动到右岸:按照某种规则从左岸列表中选取一个列表项(选取的条件是左岸不存在“危险”),将该列表项添加到右岸列表中,并从左岸列表中删除该项;然后从右岸返回左岸:如果右岸列表中存在“危险”,则从右岸列表中选取一项,转移到左岸列表中。重复上述操作,直至左岸列表为空。以上是我们解决问题的核心算法。

 

除了上述的数据结构及算法外,还需要制定一个移动的规则,与解决汉诺塔问题相似的规则是,不能连续移动某个物品。

 

有了以上结论,我们可以开始编写程序了。

 

三、设计简单的用户界面

如图1所示,用户界面非常简单,一个水平布局组件中容纳了两个标签组件,组件的属性设置见图中的文字。上传一个河流的图片素材文件,把它设为水平布局组件的背景图。计时器组件采用默认设置。

农夫过河——狼羊菜问题

图1 应用的用户界面

 

四、编写程序

1、声明全局变量

如图2所示,声明了4个全局变量,其中的对照表是一个键值对列表,用来保存物品与数字之间的关系,左岸及右岸列表用于保存两岸的物品,左到右用来保存当前的移动方向——从左到右或从右到左。

农夫过河——狼羊菜问题

图2 项目中的全局变量

 

2、创建过程

(1) 有返回值过程——危险

如图3所示,给定两个参数n1与n2,当它们差值的绝对值等于1时,返回值为真。

农夫过河——狼羊菜问题

图3 有返回值过程——危险

 

(2) 有返回值过程——被移动项

如图4所示,有返回值的过程——被移动项,返回初始状态时左岸列表中的确保安全的被移动项,返回值为数字1、2或3。

农夫过河——狼羊菜问题

图4 有返回值过程——被移动项

 

(3) 有返回值过程——显示文字

如图5所示,该过程的参数数字列表,可能是左岸列表或右岸列表,该过程将列表中的数字转化为对应的文字,以便在屏幕上显示直观的内容。

农夫过河——狼羊菜问题

图5 有返回值过程——显示文字

 

(4) 过程——显示移动结果

如图6所示,该过程将左岸及右岸列表中的数字转化为文字,并分别显示在左岸及右岸标签上。

农夫过河——狼羊菜问题

图6 显示移动结果过程

 

(5) 过程——右移物品

如图7所示,右移物品过程有两个分支:在初始状态下,从3个列表项中选出一个安全的可移动项;在其余状态下,选择列表中的第一项作为移动项。移动物品的操作由添加和删除列表项来完成,然后将移动结果显示在标签中(调用显示移动结果过程),最后,将移动状态改为从右到左(全局变量左到右=假)。

农夫过河——狼羊菜问题

图7 右移物品过程

 

(6) 过程——左移物品

如图8所示,该过程只处理右岸有两件物品且存在危险的情形。当存在危险时,选择右岸列表中的第1项作为被移动项,想想看为什么?

农夫过河——狼羊菜问题

图8 左移物品过程

 

在右移物品过程里,我们将被移动项添加到了右岸列表的结尾,因此,为了确保不连续移动,就必须选择列表中的第1项为被移动项。

 

3、  事件处理程序

如图9所示,当屏幕初始化时,显示左岸及右岸列表的内容,然后,每当到达计时点是,根据全局变量左到右的值,分别执行不同的移动操作,直到左岸列表为空时,让计时器停止计时,程序运行结束。

农夫过河——狼羊菜问题

图9 事件处理程序

 

至此这个问题已经得到解决,测试结果如图10所示,左图为起始状态,右图为完成状态。

农夫过河——狼羊菜问题

图10 项目的测试结果

您必须 登录 才能发表评论!