农夫过河 (BFS)(队列)
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)(队列)的更多相关文章
- POJ 3278 Catch That Cow[BFS+队列+剪枝]
第一篇博客,格式惨不忍睹.首先感谢一下鼓励我写博客的大佬@Titordong其次就是感谢一群大佬激励我不断前行@Chunibyo@Tiancfq因为室友tanty强烈要求出现,附上他的名字. Catc ...
- BFS 队列
Plague Inc. is a famous game, which player develop virus to ruin the world. JSZKC wants to model thi ...
- 拆边+BFS队列骚操作——cf1209F
这个拆边+队列操作实在是太秒了 队列头结点存的是一个存点集的vector,1到这个点集经过的路径权值是一样的,所以向下一层拓展时,先依次走一遍每个点的0边,再走1边...以此类推,能保证最后走出来的路 ...
- POJ——3278 Catch That Cow(BFS队列)
相比于POJ2251的三维BFS,这道题做法思路完全相同且过程更加简单,也不需要用结构体,check只要判断vis和左右边界的越界情况就OK. 记得清空队列,其他没什么好说的. #include< ...
- hdoj 2612 Find a way【bfs+队列】
Find a way Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 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 ...
- HDU 6171 Admiral(双向BFS+队列)题解
思路: 最大步骤有20,直接BFS会超时. 因为知道开始情况和结果所以可以用双向BFS,每个BFS规定最大步骤为10,这样相加肯定小于20.这里要保存每个状态搜索到的最小步骤,用Hash储存.当发现现 ...
- 剑指offer:对称的二叉树(镜像,递归,非递归DFS栈+BFS队列)
1. 题目描述 /** 请实现一个函数,用来判断一颗二叉树是不是对称的. 注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的 */ 2. 递归 思路: /** 1.只要pRoot.left和 ...
- bfs(队列模板)
[题目描述] 当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单. 假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路. [输 ...
随机推荐
- WPF自定义LED风格数字显示控件
原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...
- 微信小程序支付结果 c#后台回调
又为大家带来简单的c#后台支付结果回调方法,首先还是要去微信官网下载模板(WxPayAPI),将模板(WxPayAPI)添加到服务器上,然后在打开WxPayAPI项目中的example文件下的 Nat ...
- matlab figure 调整大小、字体、线宽
用 matlab 画了一张图,投稿时要缩小,缩小后字体就会过小或者发虚. 解决办法: % figure resize set(gcf,'Position',[100 100 260 220]); se ...
- 解决ASP.NET中Redis 每小时6000次访问请求的问题
原文:解决ASP.NET中Redis 每小时6000次访问请求的问题 虽然ServiceStack v4是商业支持的产品,但我们也允许免费使用小型项目和评估目的.上面的NuGet包中包含可以使用许可证 ...
- Invalid default value for 'created_at'
https://github.com/laravel/framework/issues/15144 https://stackoverflow.com/questions/30555844/larav ...
- socket 主机地址相关的函数
#include <arpa/inet.h> int inet_aton (const char *name, struct in_addr *addr) 将ipv4地址从数字点的形式转化 ...
- WPF DataGrid的LoadingRow事件
<Window x:Class="DataGridExam.MainWindow" xmlns="http://schemas.microsoft.c ...
- WPF IDataErrorInfo使用-数据对象上验证
<Window x:Class="DataBindingExam.MainWindow" xmlns="http://schemas.microsof ...
- iOS UITableView动态隐藏或显示Item
通过改变要隐藏的item的高度实现隐藏和显示item 1.创建UITableView #import "ViewController.h" @interface ViewContr ...
- PHP XDebug Sublime Text 单步调试
前置环境:已经安装好LNMP 1. 安装xdebug 可以通过pear包管理来安装 sudo apt-get install php-pear sudo pecl install xdebug 这里我 ...