1 、问题描述

要求设计实现农夫过河问题(农夫带着一只狼,一只养,一棵白菜,一次只能带一个东西)如何安全过河。

2 、问题的解决方案:

可以用栈与队列、深度优先搜索算法及广度优先搜索算法相应的原理去解决问题。

1)   实现四个过河对象(农夫、白菜、羊和狼)的状态,可以用一个四位二进制数来表示,0表示未过河,1表示已经过河了。

2)   过河的对象必须与农夫在河的同一侧,可以设计函数来判断。

3)   防止状态往复,即农夫将一个东西带过去又带回来的情况发生,需将所有可能的状态进行标定。

4)   可用深度优先搜索算法及广度优先搜索算法去解题。

分析:对于这道课程设计题我一开始并没有思路,在网上搜索了很多的方法,发现广度优先搜索相对好一些。运用的是位运算方法,位运算的方法在程序中的确运算方便且速度快,但不便于我们去理解,我们可以直接在定义成一个字符串进行操作对象状态,这样子相对好理解一些。

  (1)初始化

  过河状态按照题目的二进制数规定即可,我在这里规定0000中第一个0代表农夫的状态、第二个0代表狼的状态、第三个0代表羊的状态、最后一个0代表白菜的状态,由于01组成的二进制数过河状态一共有16中情况,定义一个route[16]的数组,用于标记已经走过的状态,顺便将标记值定义为前驱状态便于查找,初始化route数组为-1(都没有经过),先把四个对象都没过河的情况(0000)放入队列,同时标记route[0]为0 (0状态没有前驱)表示已经经过。

  (2)搜索

  将第一个状态入队后,从队头取出进行搜索。先考虑三种情况,农夫是否能带狼、羊、白菜过河,先判断农夫跟这三个对象是否在同一个地方。如果在同一个地方,再假设如果换位之后,其状态是否合法。即羊不会被狼吃掉,白菜不会被羊吃掉,同时这个假设的状态之前还没有经过。如果这些条件都成立,那么这种过河方式就可以使用,标记状态,并将他放入队尾。把这三种情况全部考虑完之后,还有一种情况就是农夫什么东西都不带过河,判断条件跟上面一样,成立就标记状态放入队尾。这样就把一次农夫过河的全部情况都考虑了,再从下次搜索中接着从对头出来的情况继续重复上面的搜索,直到找到能使状态为1111的情况,这一定是最先找到的情况。

  (3)输出步骤

  route详细记录了每个状态的前驱,我们从route[15]对应值找前驱,再从前驱找其对应前驱,直到找到route[0]为止。这样的话就倒序输出了农夫过河的最佳路径

  实现代码

 #include<string>
#include<stdio.h>
#include<iostream>
#include<queue>
#include<stdlib.h>
using namespace std;
queue<string>st;//定义一个队列用来存放合法状态
string a="";
string b,c;
int route[],temp,l,r;
//0代表农夫 1代表狼 2代表羊 3代表菜
bool check(char a1 ,char b1,char c1,char d1)//定义函数来检测合法状态
{
if((a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')||
(a1==''&&b1==''&&c1==''&&d1=='')
)
return true;
else return false;
}
int bfs()
{
for(int i=;i<=;i++)//初始化route数组
route[i]=-;
st.push(a);//将初始状态放入队尾
route[]=;//标记初始状态以经过
int test1=,test2=;//test1表示当前状态(十进制),test2表示假设状态(十进制)
while(!st.empty()&&route[]==-)//如果队列不空或者都没有到达对岸就继续搜索
{
b=st.front();//获取队头状态
test1=*(b[]-'')+*(b[]-'')+*(b[]-'')+*(b[]-'');//将状态转化为十进制
st.pop();将队头状态弹出
for(int i=;i<=;i++)//判断农夫是否能带三种对象过河
{
c=b;//为了不破坏状态用c来代替
if(b[]==b[i])//如果农夫和其中一个对象在同一个地方
{
if(c[]=='')//如果是0就过河换为1
{
c[]='';
c[i]='';
}
else//如果是1就过河换为0
{
c[]='';
c[i]='';
}
test2=*(c[]-'')+*(c[]-'')+*(c[]-'')+*(c[]-'');//将假设状态转化为十进制
if(check(c[],c[],c[],c[])&&route[test2]==-)//如果假设情况过河后状态是合法的同时这种状态还没有经过
{
st.push(c);//将这种状态放入队列中
route[test2]=test1;//标记这种状态已经经过
}
}
}
c=b;//这种情况是考虑农夫不带任何东西过河,与上面判断情况相同
if(c[]=='')
{
c[]='';
}
else
{
c[]='';
}
test2=*(c[]-'')+*(c[]-'')+*(c[]-'')+*(c[]-'');
if(check(c[],c[],c[],c[])&&route[test2]==-)
{
st.push(c);
route[test2]=test1;
}
}
if(route[]!=-)//如果最终全部都过了河,倒序输出过河步骤
{
cout<<"15 1111"<<endl;//15情况没有后继直接输出
for(int i=;i>;i=route[i])
{
cout<<route[i]<<" ";//输出该状态对应前驱
if(route[i]<)
cout<<' ';
switch(route[i])//输出该状态十进制数对应的二进制数
{
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
case :cout<<""<<endl;break;
}
if(i==)
break;
}
}
}
int main()
{
bfs();
}

农夫过河 (BFS)(队列)的更多相关文章

  1. POJ 3278 Catch That Cow[BFS+队列+剪枝]

    第一篇博客,格式惨不忍睹.首先感谢一下鼓励我写博客的大佬@Titordong其次就是感谢一群大佬激励我不断前行@Chunibyo@Tiancfq因为室友tanty强烈要求出现,附上他的名字. Catc ...

  2. BFS 队列

    Plague Inc. is a famous game, which player develop virus to ruin the world. JSZKC wants to model thi ...

  3. 拆边+BFS队列骚操作——cf1209F

    这个拆边+队列操作实在是太秒了 队列头结点存的是一个存点集的vector,1到这个点集经过的路径权值是一样的,所以向下一层拓展时,先依次走一遍每个点的0边,再走1边...以此类推,能保证最后走出来的路 ...

  4. POJ——3278 Catch That Cow(BFS队列)

    相比于POJ2251的三维BFS,这道题做法思路完全相同且过程更加简单,也不需要用结构体,check只要判断vis和左右边界的越界情况就OK. 记得清空队列,其他没什么好说的. #include< ...

  5. hdoj 2612 Find a way【bfs+队列】

    Find a way Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. poj 3278 Catch That Cow(bfs+队列)

    Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...

  7. HDU 6171 Admiral(双向BFS+队列)题解

    思路: 最大步骤有20,直接BFS会超时. 因为知道开始情况和结果所以可以用双向BFS,每个BFS规定最大步骤为10,这样相加肯定小于20.这里要保存每个状态搜索到的最小步骤,用Hash储存.当发现现 ...

  8. 剑指offer:对称的二叉树(镜像,递归,非递归DFS栈+BFS队列)

    1. 题目描述 /** 请实现一个函数,用来判断一颗二叉树是不是对称的. 注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的 */ 2. 递归 思路: /** 1.只要pRoot.left和 ...

  9. bfs(队列模板)

    [题目描述] 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单. 假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路. [输 ...

随机推荐

  1. 图形的认识(curve,surface,hypersurface)

    平滑函数(smooth function): curve:曲线: 二维平面: surface:曲面: 三维空间: hypersurface:超曲面: 更高维度: 1. surface 是对平面的泛化, ...

  2. WPF获取外部EXE图标最简单的方法

    原文:WPF获取外部EXE图标最简单的方法 首先在工程添加对System.Drawing的引用 创建以下方法: public static ImageSource GetIcon(string fil ...

  3. 在运行Hfile的MR如果任务client结束OOM

    在运行MR将HDFS转换成HFile什么时候.例如,会发生以下的异常: 14/07/09 18:02:59 INFO mapred.JobClient:  map 83% reduce 0% 14/0 ...

  4. 数据在数组中存储的顺序:小端 OR 大端模式 详解

    大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放: 小端模式,是指数据的高 ...

  5. Win8Metro(C#)数字图像处理--2.6图像对比度调整

    原文:Win8Metro(C#)数字图像处理--2.6图像对比度调整  2.6图像对比度调整函数 [函数名称] 图像对比度调整函数ContrastAdjustProcess(WriteableBi ...

  6. 【redis】redis的bind配置

    原文:[redis]redis的bind配置   在配置文件redis.conf中,默认的bind 接口是127.0.0.1,也就是本地回环地址.这样的话,访问redis服务只能通过本机的客户端连接, ...

  7. kafka 遇到的错

    D:\cluster\kafka_2.->.\bin\windows\kafka-topics.bat --create --zookeeper localhost: --replication ...

  8. .NET Core2.1项目在Linux上使用验证码报Unable to load shared library 'gdiplus' or one of its dependencies

    -- ::, 线程ID:[] 日志级别:ERROR 出错类:WebApp.HttpGlobalExceptionFilter property:[(null)] - 错误描述:System.TypeI ...

  9. DELPHI XE2 采用 JSON 的方式来序列化对象

    DELPHI XE2 采用 JSON 的方式来序列化对象 以下代码测试通过.问题是里面的中文,在反序列化后是乱码. 1. 序列化对象为字符串,Subject 里面的中文看起来正常,仍然是中文: 2.  ...

  10. 国家气象局 天气预报 城市代码(JSON格式)

    如题 { "城市代码": [ { "省": "北京", "市": [ { "市名": "北 ...