农夫过河问题(农夫、狼、羊和白菜的问题),描述如下:

一个农夫,带着一只狼、一只羊、和一棵白菜,身处河的南岸,他要把这些东西全部运到北岸。农夫的面前有一条小船,船小到只能容下他和一件物件。另外,只能农夫会撑船。又因为狼能吃羊,而羊爱吃白菜,所以农夫不能留下羊和白菜而自己离开,也不能留下狼和羊而自己离开。但狼属于食肉动物,不吃白菜。

问农夫采取什么方案才能将所有的东西运过河?

解题思路

农夫过河问题的求解方法是使用要实现广度优先搜索,一般采用把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别对其进行处理,处理过程中再把下一步的状态放在队列里。

在采用编程解决农夫过河的问题时,首先需要考虑以下几个问题:

程序中为了方便描述农夫过河过程中几个角色的位置(位于南岸还是北岸),最好的方法是用 4 个二进制数,分别

为了方便获取各个角色当前所在的位置,程序中设置了如下 4 个函数。其中,函数返回值为 1,反之则表示角色在河的北岸:

//表示农夫状态的函数,返回0 ,表示农夫在南岸,反之在北岸。

int farmer(int location){

return(0!=(location & 0x08));

}

//表示狼的状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int wolf(int location){

return(0!=(location & 0x04));

}

//表示白菜状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int cabbage(int location){

return(0!=(location & 0x02));

}

//表示羊状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int goat(int location){

return(0!=(location & 0x01));

}

其中,location 为当前 4 种角色所处的状态,其值为 0(0000) 到 15(1111) 之间的数。通过 location 与不同角色二进制的按位与运算,可获得当前状态下各个角色的位置。

任何角色移动后,都需要进行判断:当前移动是否是有问题的。例如,当农夫不在的情况下,是否狼和羊同时在一起,又或是羊和白菜同时在一起,这两种情况都是不安全的。所以该函数应该写为:

//判断当前状态是否合理的函数

int safe(int location){

//如果农夫不在羊身边,而羊和白菜在一起,则为不安全

if(goat(location) == cabbage(location) && goat(location) != farmer(location)){

return 0;

}

//如果农夫不在狼身边,而狼和羊在一起,也不安全

if(goat(location) == wolf(location) && goat(location) != farmer(location)){

return 0;

}

//其他情况都安全

return 1;

}

为了记录各个角色的移动过程,程序中设置了

初始状态下,route 中的每个分量都为 -1,每当在队列中加入一个新状态时,就把数组中与该状态对应的位置的值改为达到此状态的前一状态的下标值。即此位置存储上一状态所在位置的下标(便于最后输出整个的移动方案)。在route数组中,一个元素具有非负值,表明这个状态已被访问过。

解决以上 4 个难题,农夫过河的问题就很简单了,实现代码如下:

#include

#include

#define MAXSIZE 100 //队列的最大长度

typedef int ElemType;

typedef struct{

ElemType data[MAXSIZE];//队列的存储空间

int front,rear;//队列的队头指针和队尾指针

}SqQueue;

//初始化队列

void Init_SqQueue(SqQueue *Q){

Q->front = Q->rear =0;

}

//判断队列是否为空

int Empty_SqQueue(SqQueue *Q){

return Q->rear == Q->front;//为真,返回1 则表示队列为空

}

//数据 e 进队列

void In_SqQueue(SqQueue *Q, int e){

if(Q->rear == MAXSIZE){

return;

}

Q->data[Q->rear] = e;

Q->rear+=1;

}

//数据出队列,通过将出队列数据赋值给 e

void Out_SqQueue(SqQueue *Q,int *e){

//出队之前,先判断队列是否为空

if(Q->rear == Q->front){

return;

}

*e = Q->data[Q->front];

Q->front+=1;

}

//表示农夫状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int farmer(int location){

return(0!=(location & 0x08));

}

//表示狼的状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int wolf(int location){

return(0!=(location & 0x04));

}

//表示白菜状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int cabbage(int location){

return(0!=(location & 0x02));

}

//表示羊状态的函数,返回0 ,表示农夫在南岸,反之在北岸

int goat(int location){

return(0!=(location & 0x01));

}

//判断当前状态是否合理的函数

int safe(int location){

//如果农夫不在羊身边,而羊和白菜在一起,则为不安全

if(goat(location) == cabbage(location) && goat(location) != farmer(location)){

return 0;

}

//如果农夫不在狼身边,而狼和羊在一起,也不安全

if(goat(location) == wolf(location) && goat(location) != farmer(location)){

return 0;

}

//其他情况都安全

return 1;

}

//农夫过河的实现函数

void farmerproblem(){

int movers,location,newlocation;

int route[16];//用于记录已考虑的状态路径

int i;

SqQueue moveto;

Init_SqQueue(&moveto);

//以所有角色都在南岸开始

In_SqQueue(&moveto,0x00);

//对记录路径的数组初始化

for(i=0;i<16;i++){

route[i] = -1;

}

//记录所有角色都在南岸的路径

route[0] = 0;

while(!Empty_SqQueue(&moveto) && (route[15] == -1)){

Out_SqQueue(&moveto,&location);//出队列,并将状态赋值给location

//依次移动羊、白菜、狼和农夫,movers每次左移一位,所以其值每次为1,2,4,8

for(movers =1;movers<=8;movers<<=1){

//判断农夫与要移动的角色是否位于河岸的同一侧

if(((location & 0x08)!=0) == ((location & movers)!=0)){

//若农夫与该角色在同一侧则尝试移至对岸(异或运算)

newlocation = location^(0x08|movers);

//判断此移动是否安全

if(safe(newlocation) && route[newlocation] == -1){

//如果安全,且之前没有移动过,则进行记录,记录方法是在新位置记录之前的移动位置

route[newlocation] = location;

//将新的移动方案入队

In_SqQueue(&moveto , newlocation);

}

}

}

}

//如果最终移动成功,即由 0000 变成 1111则视为成功

if(route[15]!=-1){

printf("the reverse path is :");

for(i=15; i>=0; i=route[i]){

printf("\n the location is:%d",i);

if(i==0){

break;

}

}

}else{

printf("no path");

}

}

int main(){

farmerproblem();

return 0;

}

运行结果为:

the reverse path is :

the location is:15

the location is:6

the location is:14

the location is:2

the location is:11

the location is:1

the location is:9

the location is:0

提示:输出的各个数字,要转化为二进制看,才有意义,例如,15,二进制为1111,表示农夫、狼、白菜和羊都在河的北岸;而最终的 0,二进制为 0000,表示其都在南岸。

农夫过河问题 matlab,农夫过河问题 宽搜(bfs)算法详解相关推荐

  1. Matlab人脸检测算法详解

    这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...

  2. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

  3. matlab 调整灰度,matlab灰度图像调整及imadjust函数的用法详解

    matlab--imadjust函数作用: 对进行图像的灰度变换,即调节灰度图像的亮度或彩色图像的颜色矩阵 在MATLAB中,通过函数imadjust()进行图像灰度的调整,该函数调用格式如下: J= ...

  4. 抓住那头牛(宽搜bfs)

    Description 农夫知道一头牛的位置,想要抓住它.农夫和牛都位于数轴上,农夫起始位于点N,牛位于点K. 农夫有两种移动方式: 1.从X移动到X−1或X+1,每次移动花费一分钟. 2.从X移动到 ...

  5. matlab插值法原理,【插值】插值方法原理详解

    插值问题详解 1. 我在具体的应用(如数学建模竞赛)中,常常需要根据已知的函数点进行数据.模型的处理和分析,而通常情况下现有的数据是极少的,不足以支撑分析的进行,这时就需要使用一些数学的方法,&quo ...

  6. matlab圆周运动表示三角函数,用代码画画-详解三角函数

    原标题:用代码画画-详解三角函数 用代码画画,必需要懂很多数学知识?如果数学基础没那么好,是否就无法肆意表达,领略其中的乐趣? 其实不然.很多时候,只要用简单的数学知识,也能做出复杂精妙的作品. 希望 ...

  7. 过河问题matlab建模,过河问题-数学建模C++实现

    经典的过河问题:一个人(猎人)带了:一只鸡(羊),一条狗(狼),一袋米(草),遇到一条河,河边有一条船,船太小每次只能带一样东西,此人如何将自己的三件物品完好的带到对岸? (注:若是VS2010开发工 ...

  8. 过河游戏(算法详解+例题)

    需求:划船过河,至少需要一个人划船,当两个人乘船时,时间由需要较长时间过河的决定.求最短的过河时间. 分析:由题设可知.最短时间肯定是用时较快的人来回跑.此时有两种情况. 首先假设A为时间最短的人,B ...

  9. php将img中的宽高删除,PHP删除HTML中宽高样式的详解

    这篇文章主要介绍了PHP正则删除HTML代码中宽高样式的方法,涉及php针对HTML代码的正则匹配.替换等操作技巧,需要的朋友可以参考下 本文实例讲述了PHP正则删除HTML代码中宽高样式的方法.分享 ...

  10. matlab中 mcc、mbuild和mex命令详解

    先简单的说说mcc.mbuild和mex到底怎么回事: mcc将M文件转换成C/C++文件和相应的MEX包裹文件(需要Matlab编辑器),但在特定条件下可以自动调用mbuild或者mex mex将C ...

最新文章

  1. asp.net ajax学习系列功能强大的UpdatePanel控件
  2. C#让程序只运行一次实例
  3. Docker 建立镜像流程
  4. kudu大量数据更新_Apache Kudu又更新?1.4版改进了Web界面
  5. 判断男人成熟度16个新标准。
  6. LightGBM 重要参数、方法、函数理解及调参思路、网格搜索(附例子)
  7. c# 正则表达式笔记
  8. python中pip的安装与使用
  9. 安卓手机能用吗_手机才用两年卡的不行,是手机问题吗,想问手机最长能用几年?...
  10. OAuth2认证授权流程解析
  11. 测试用例之因果图分析法
  12. ELK日志分析平台之kibana以及借助ELK平台实现网站访问量统计
  13. 天猫淘宝越来越难做了,为什么不考虑下跨境电商?
  14. 什么是LED晶膜屏?和透明LED贴膜透明屏一样吗?
  15. 华为认证网络工程师考试是中文吗?
  16. 什么是EasyAntiCheat.exe,为什么在我的计算机上?
  17. 用C语言,职工信息管理系统
  18. 修改源码实现小程序UI库iview weapp的modal组件自定义宽高
  19. 桂电七院数据库实验报告四
  20. 上海三菱电梯LEHY,LEGY,上海三菱,758 .778详 细地址码,总共100多页

热门文章

  1. 斯坦福NLP笔记6 —— Defining Minimum Edit Distance
  2. 在eclipse中创建web项目
  3. NDB的备份和恢复---测试start backup和ndb_restore
  4. 换一种途径看信息,享受快捷 RSS阅读----willack.liu[原创]
  5. Objective-C中的位运算符用法
  6. idea2020在工具栏显示前进和后退箭头
  7. CSS 样式里面的逗号和空格之间的区别
  8. Facebook F8|闲鱼高级技术专家参会分享
  9. Navicat Premium之MySQL客户端的下载、安装和使用(博主推荐)
  10. Linux 设置时区 命令