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. #748 – 获得按下时对应位置点的大小(Getting the Size of a Contact Point during Raw Touch)

    原文:#748 – 获得按下时对应位置点的大小(Getting the Size of a Contact Point during Raw Touch) 原文地址:https://wpf.2000t ...

  2. win7(64bit)使用mingw64配置gtkmm

    因为linux命令不熟悉,加上时间不充裕,仍然决定在win7_64bit下开发GUI程序,选择gtkmm是因为: 1. 在图形界面程序中,windows系统当之无愧GUI之王,用户友好性其他OS无法替 ...

  3. 如何自定义WPF项目的Main函数

    原文:如何自定义WPF项目的Main函数 与Winform项目不同,WPF项目的Main函数在项目生成的时候,系统自动在后台为我们生成.根据项目生成方式的不同,其文件位于obj/Debug/App.g ...

  4. WPF 过滤集合

    <Window x:Class="ViewExam.MainWindow"        xmlns="http://schemas.microsoft.com/w ...

  5. jquery QQ微博

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. C++中类的继承与Java中的不同,C++的派生类不能继承父类的构造函数和析构函数(不一定正确)

    http://blog.csdn.net/guodongxiaren/article/details/24885023

  7. RSA加密解密及RSA签名和验证

    原文:RSA加密解密及RSA签名和验证 1.RSA加密解密: (1)获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥 (2)加密 (3)解密2.RSA签名和验证 (1)获取密钥,这里是 ...

  8. GIS基础软件及操作(四)

    原文 GIS基础软件及操作(四) 练习四.空间数据处理 1.空间数据处理(融合.合并.剪切.交叉.合并)2.设置地图投影及投影变换 空间数据处理 数据:云南县界.shp; Clip.shp西双版纳森林 ...

  9. SFC游戏列表(维基百科)

    SFC游戏列表 日文名 中文译名 英文版名 发行日期 发行商 スーパーマリオワールド 超级马里奥世界 Super Mario World 1990年11月21日 任天堂 エフゼロ F-Zero F-Z ...

  10. C语言中.h和.c文件解析(转载)

    转载:http://www.cnblogs.com/laojie4321/archive/2012/03/30/2425015.html   简单的说其实要理解C文件与头文件(即.h)有什么不同之处, ...