农夫过河 (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的迷宫的图纸,请你找出从起点到出口的最短路. [输 ...
随机推荐
- 零元学Expression Design 4 - Chapter 2 熟悉Design并且快速设计出Silverlight网页
原文:零元学Expression Design 4 - Chapter 2 熟悉Design并且快速设计出Silverlight网页 本章将用带大家熟悉Design 4并制作简易的网页版面,也会让你了 ...
- 【树转数组】poj1195
/* 二维的树状数组: 更新某个元素时: NO.1:c[n1],c[n2],c[n3],....,c[nm]; 当中n1 = i,n(i+1) = ni+lowbit(ni); nm+lowbit(n ...
- Mybatis 一对多 配置文件
当一个Entity中包含的属性有对象和对象集合时,用mybatis映射时要在Entity中添加一个字段来唯一标识当前的Entity对象.否则查询的Entity集合中的对象会被覆盖掉. 如下一个POJO ...
- AngularJS 计时器
<div ng-controller="MyController"> <!--显示$scope.clock的now属性--> <h1>hello ...
- python3 提示No module named _sqlite3
yum install sqlite-devel 下载python3.6.3 重新编译安装 ./configure --enable-loadable-sqlite-extensions & ...
- wpf 路由事件 代码片段
<?xml version="1.0" encoding="utf-8" ?> <CodeSnippets xmlns="http: ...
- 程序定义了多个入口点。使用 /main (指定包含入口点的类型)进行编译
原文:请使用/main进行编译,以指定包含入口点类型 在使用VS工具初学C#的时候需要不停的写小程序,觉得每次都新建项目太过麻烦,所以试着把程序写在一个项目下面,结果编译的时候出错了,因为我每个小程序 ...
- 微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API
原文:微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API 反正我是没有测通这两个API!!!!不知道用的方式不对还是其他的!! ...
- 微信小程序把玩(十七)input组件
原文:微信小程序把玩(十七)input组件 input输入框使用的频率也是比较高的...样式的话自己外面包裹个view自己定义.input属性也不是很多,有需要自己慢慢测,尝试 主要属性: wxml ...
- Linux ACL对某一些文件有管理权限
某些系统账号希望对某一些文件有管理权限,有三种方法: 1 加入属主所在的同一个组中,这等于扩大了访问其他文件的权限了. 2 加入other中,这样权限放开的更大了. 3 给文件的sudo权限. 4 采 ...