过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(第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岸,则说明找到了一条完整的“状态路径”,这时需要打印这条路径,并清除当前状态的访问标记,且退出上一个状态,继续寻找下一种可能性。

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

源码示例

结果展示

小结

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

时间: 2024-09-29 09:41:07

过河问题(牛虎过河、商人仆人过河、农夫妖怪过河、传教士野人过河)(第2届第2题)的相关文章

传教士与野人过河问题(A*搜索 C++)

传教士与野人过河问题: 任意时刻,左岸.右岸.船上如果传教士人数少于野人人数,传教士就会被野人吃掉.当然野人会划船.传教士人数为0也是可以的. 启发函数 f=g+h.  g当前结点所在解空间树的深度.h=m+c-2*b. m,c分别是当前状态下左岸传教士和野人的数目.b=1表示当前船在左岸停靠.b=0表示当前状态船在右岸. #include<vector> #include<algorithm> #include<stdio.h> #include<stdlib.

【数学模型】商人们怎样过河?

这篇博文中,同样是一个很简单的数学问题,但是解决起来比上一个的问题要复杂一些.在这次模型求解中,我会使用两种方法,一种是纯粹的数学方法,另一种是通过计算机程序来计算,通过计算机求解我们可以求解一些规模更大的问题.由于这篇文章篇幅我预计会比较长,为了不混淆,上一篇文章<椅子能在不平的地面上放平吗?>中的延伸问题我会再写一篇文章单独解答. 问题引出 问题: 三名商人各带一个随从过河,一只小船只能容纳两个人,随从们约定,只要在河的任何一岸,一旦随从人数多于商人人数就杀人越货,但是商人们知道了他们的约

花了半个晚上写了一个深度优先求解人狼过河的程序

狼人过河问题:有三个人和三只狼要过河,河里有一只船同时能容纳最多两个生物假设狼和人都会划船,但如果岸边(不包括船上)狼的数量比人多 ,狼就要吃人问:怎么把三只狼和三个人安全运输到对岸 1 // mytest.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include <windows.h> 6 #include <iostream> 7 #include <string> 8 #inclu

过河问题--nyoj题目47

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过.如果各自单独过桥的话,N人所需要的时间已知:而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间.问题是,如何设计一个方案,让这N人尽快过桥. 输入 第一行是一个整数T(1<=T<=20)表示测试数据的组数每组测

nyoj 47 过河问题

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过.如果各自单独过桥的话,N人所需要的时间已知:而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间.问题是,如何设计一个方案,让这N人尽快过桥. 输入 第一行是一个整数T(1<=T<=20)表示测试数据的组数每组测

Laoj P1283 过河问题

试题描述 在一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸.而东岸边有一条小船.船太小了,一次只能乘坐两人,每个人都有一个渡河时间T,船划到对岸的时间等于船上渡河时间较长的人所用的时间.现在已知N个人的渡河时间T,Oliver想要你告诉他,他们最少要花费多少时间,才能使所有人都过河.注意,只有船在东岸(西岸)时东岸(西岸)的人才能坐上船划到对岸. 输入格式 输入文件第一行为人数N,以下有N行,每行一个数. 第i+1行的数为第i个人的渡河时间. 输出格式  输

南阳47(过河问题)

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过.如果各自单独过桥的话,N人所需要的时间已知:而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间.问题是,如何设计一个方案,让这N人尽快过桥. 输入 第一行是一个整数T(1<=T<=20)表示测试数据的组数每组测

过河问题(南阳oj47)(贪心)

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过.如果各自单独过桥的话,N人所需要的时间已知:而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间.问题是,如何设计一个方案,让这N人尽快过桥. 输入 第一行是一个整数T(1<=T<=20)表示测试数据的组数 每组

过河问题 贪心

过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的.不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过.如果各自单独过桥的话,N人所需要的时间已知:而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间.问题是,如何设计一个方案,让这N人尽快过桥. 输入 第一行是一个整数T(1<=T<=20)表示测试数据的组数每组测