农夫过河 (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的迷宫的图纸,请你找出从起点到出口的最短路. [输 ...
随机推荐
- sql语句计算出每个月的天数
原文:sql语句计算出每个月的天数 从当前月-11个月开始,到当前月为止,用一个sql语句计算出每个月的天数. SELECT TO_CHAR(ADD_MONTHS(SYSDATE,-LEVEL+1 ...
- c#-WPF string,color,brush之间的转换
原文:c#-WPF string,color,brush之间的转换 String转换成Color string-"ffffff" Color color = (Color)Colo ...
- ZOJ 3819 Average Score(数学 牡丹江游戏网站)
主题链接:problemId=5373">http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5373 Bob is ...
- 【codeforces】Codeforces Round #277 (Div. 2) 解读
门户:Codeforces Round #277 (Div. 2) 486A. Calculating Function 裸公式= = #include <cstdio> #include ...
- EasyUI-DataGrid多线动态实现选择性合并
jQuery EasyUI有一个非常易于使用的数据列表控件,这是DataGrid控制.某些背景json格式可以传递给在前景中显示的控制,很强大.只要有时需求须要这样即多行合并,如在列表中假设同样的部门 ...
- 【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)
原文:[C#/WPF]调节图像的HSL(色相.饱和度.明亮度) 先说概念: HSL是一种描述颜色的方式(其他颜色描述方式还有大家熟悉的RGB值).HSL三个字母分别表示图像的Hue色相.Saturat ...
- WPF 4 开发Windows 7 任务栏(Overlay Icon、Thumbnail Toolbar、Progress Bar)
原文:WPF 4 开发Windows 7 任务栏(Overlay Icon.Thumbnail Toolbar.Progress Bar) 在上一篇我们介绍了如何在WPF 4 中开发Wind ...
- WPF VisualTreeHelper的使用
<Window x:Class="MyWpf.MainWindow" xmlns="http://schemas.microsoft.com/winf ...
- 一个由单例模式在多线程环境下引发的 bug
问题症状 HTTP 日志系统,老是出现日志信息覆盖的情况.比如同时调用 A 接口和 B 接口,B 接口请求响应信息变成了 A 接口请求响应相关信息.这个问题在并发量大的情况下越来越严重. 问题初步分析 ...
- 用MVVM模式开发中遇到的零散问题总结(3)——自制正则表达式万能绑定转换器
原文:用MVVM模式开发中遇到的零散问题总结(3)--自制正则表达式万能绑定转换器 前言 最近接受了3个项目的洗礼,出差近3个月,各种北京.广州.昆明来回奔波,好久没写博客了,之前我觉得我遇到的问题都 ...