过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题) 题目要求 解决方案 源码示例 结果展示 小结

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结

       问题描述:三只牛三只虎过河,船最多只能容纳两只动物,且船在往返途中不能为空。在任一岸边,若牛的数量少于虎的数量,则牛就会被老虎吃掉。为了使动物全部过河且使无损失,请制定合理的渡河方案。

解决方案

       这也是一个经典的渡河问题了,由此衍化出的版本有商人仆人(随从)过河,农夫妖怪过河,传教士野人过河...除了角色有变化,内容本质上是一样的。

       假设原来的动物和船都在A岸,现在想渡河到对面的B岸。考虑牛虎数量和船的位置,可以将本题中的所有可能出现的情形描述为静态属性动态属性。静态属性就是船停靠在A岸或者B岸时,A岸牛、虎的数量(A岸数目一定时,B岸也一定,所以只需考虑一边就行),动态属性就是船在运行中时,A岸或者B岸牛、虎的数量。

       进一步考虑,只要知道了相邻的两个静态属性,也就知道了发生在其间的动态属性。比如开始船在A岸,A岸有牛、虎各三只,下一个状态为船在B岸,A岸有牛虎各两只,那它们之间的动态属性一定是船由A到B,且运送了一牛一虎过去(不考虑重复的状况)。所以在这里,我们只需要确定每一步对应的静态属性,在编程中,将其描述为状态。对于岸边的牛或者虎的数量,只有0到3这四个取值,对于船的停靠位置,只有A岸和B岸两种情形,这样一来,就有了4*4*2=32种状态。在这32种状态中,有些状态会引起牛吃虎,这必须被排除掉。

       到这里,制定渡河方案的问题就转换为在这32个状态中探寻合理“状态路径”的问题。我们从初始状态——A岸牛虎各三只,船在A岸这个状态出发,不断判断遇到的下一个状态是否合理。如果下一个状态合理,就将其加入到“状态路径”当中,并留下访问标记(防止重复添加,形成环路),否则,跳过此状态。在不断向前探寻的过程中,如果遇到一个标记为已访问的状态,说明该状态已加入路径,需要探寻下一种可能。如果遇到了结束状态——A岸牛虎为零,船在B岸,则说明找到了一条完整的“状态路径”,这时需要打印这条路径,并清除当前状态的访问标记,且退出上一个状态,继续寻找下一种可能性。

       在具体编程中,可以利用来存储初始状态到结束状态的所有状态,目的是为了在遇到不符合题意的状态时,可以原路返回,便于回溯。由于在推进过程中,每个状态都是基于对岸边牛虎数量和船的停靠位置的判断,所以,考虑用递归会更容易。但值得注意的是,这里的递归并不像斐波那契数列那样不断衍生出先决条件,而是更类似于“尾递归”,边递归,边推进,即递归的外壳迭代的内心

源码示例

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结

结果展示

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(内测第2届第2题)
题目要求
解决方案
源码示例
结果展示
小结

小结

       一个经典的过河问题,本质就是在各状态之间寻求符合题意的状态路径,在有多条路径的情形下,需要使用栈保存之前的各个状态,以便在遇到不符合条件的状态时可以回溯。这种回溯思想在迷宫寻路问题和八皇后问题中都有体现。可以说是一母同胞,属于同一类型的问题。