1、目标

通过本文,希望可以达到以下目标,当遇到任意问题时,可以:

  1、很快建立状态空间;

  2、提出一个合理算法;

  3、简单估计时空性能;

2、搜索分类

2.1、盲目搜索

  按照预定的控制策略进行搜索,在搜索过程中获得的中间信息不用来改进控制策略;

  常见算法:

  1、广度优先搜索(Breadth First Search);

  2、深度优先搜索(Depth First Search);

  3、纯随机搜索、重复式搜索、迭代加深搜索、迭代加宽搜索、柱形搜索;

2.2、启发式搜索

  在搜索中加入了与问题有关的启发性信息,用以指导搜索朝着最有希望的方向发展,加速问题的求解过程并达到最优解。

  常见算法:

  1、A*算法;

  2、IDA*算法;

3、状态空间

状态

  问题在某一时刻进展状况的数学描述;

状态转移

问题从一种状态转移到另一种或几种状态的操作;

状态空间

一个“图”,图结点对应于状态,点之间的边对应于状态转移;

搜索

寻找一种可行的操作序列,从起始状态经过一系列状态转移,达到目标状态;

4、过河问题

某人带一条狗、一只鸡、一筐米过河,但小船除了需要人划动外,最多可以带一个物品,而人不在场时,狗要吃鸡,鸡要吃米。问此人应该如何过河?

4.1、问题分析

状态:建立四元组(人,狗,鸡,米)。0表示在左岸,1表示在右岸。

起始状态:(0,0,0,0)

终止状态:(1,1,1,1)

状态转移规则(操作,用1-x来表示过一次河,无论是到左岸还是到右岸都可以):

(a,b,c,d)

  →(1-a,1-b,c,d)(当a=b)【人带狗过河】

  →(1-a,b,1-c,d)(当a=c)【人带鸡过河】

  →(1-a,b,c,1-d)(当a=d)【人带米过河】

  →(1-a,b,c,d)                 【人自己过河】

约束条件:

(a,b,c,d)中,a≠b时b≠c,a≠c时c≠d

4.2、直观的搜索过程

首先从初始状态开始:

然后再对两个可能状态进行进一步搜索:

搜索在“图”中进行,但是图不需要事先建立(“隐式图”);

搜索过程就是对图的遍历过程,可以得到一课“搜索树”;

搜索树的结点个数、分支数、深度,决定着搜索的效率;

存储和算法

  普通状态可以用4个整数表示;

  压缩状态可以用4个bit表示;

  用BFS或DFS;

5、BFS基本结构

BFS搜索过程没有回溯,是一种牺牲空间换取时间的方法。时间复杂度:O(V+E)

 定义一个队列;
起始点加入队列;
while(队列不空){
取出队头结点;
若它是所求的目标状态,跳出循环;
否则,从它扩展出子节点,全都添加到队尾;
}
若循环中找到目标,输出结果;
否则输出无解;

6、BFS例题

6.1 HDOJ1242 Rescue

Description:

Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison.
Angel's friends want to save
Angel. Their task is: approach Angel. We assume that "approach Angel" is
to get to the position where Angel stays. When there's a guard in the
grid, we must kill him (or her?) to move into the grid. We assume that
we moving up, down, right, left takes us 1 unit time, and killing a
guard takes 1 unit time, too. And we are strong enough to kill all the
guards.
You have to calculate the minimal time to approach Angel.
(We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within
bound, of course.)

Input:

First line contains two integers stand for N and M.
Then N lines
follows, every line has M characters. "." stands for road, "a" stands
for Angel, and "r" stands for each of Angel's friend.
Process to the end of the file.

Output:

For each test case, your program should output a single integer, standing for the minimal time needed. If such a number does no exist, you should output a line containing "Poor ANGEL has to stay in the prison all his life."

Sample Input:

 #.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........

Sample Output:

 

Code 1:

 //这是一个比较标准的bfs,没有经过任何优化,但是思路比较清晰,容易看懂。
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
//node结构体
typedef struct
{
int x;
int y;
int len;
}node;
//全局变量定义
#define M 202
char Map[M][M];//地图
int mask[M][M];//访问标志
queue<node> q;//队列,只在bfs中用到
int bx,by,ex,ey,w,h;//起点、终点、宽、高
int step[][] = {//四个方向
//0-up
,-,
//1-right
,,
//2-down
,,
//3-left
-,
}; void readMap(int m,int n);//读取地图
void bfs();//bfs
int tryXY(int x,int y);//尝试x、y点 void main()
{
while (scanf("%d %d",&h,&w)==)
{
readMap(h,w);
bfs();
cout<<mask[ex][ey]<<endl;
}
} void readMap(int m,int n)//m-h,n-w
{
int i,j;
for (i=;i<m;i++)
{
for (j=;j<n;j++)
{
cin>>Map[i][j];
mask[i][j] = -;//标志为未访问
if (Map[i][j] == 'r')
{//friend为起点,且化为road
Map[i][j] = '.';
bx = i; by = j;
}
if (Map[i][j] == 'a')
{//angel为终点,且化为road
Map[i][j] = '.';
ex = i; ey = j;
}
}
}
} void bfs()
{
node n,m;//m为队头,n为m衍生的测试点
int i,ret;
//起点
m.x = bx;
m.y = by;
m.len = ;//len
mask[bx][by] = ;//ask
q.push(m);//push
//处理
while (q.size())
{
//get front
m = q.front();
q.pop();
//test node m
for (i= ; i< ; i++)
{
n.x = m.x+step[i][]; n.y = m.y+step[i][]; n.len = m.len+;
ret = tryXY(n.x,n.y);
switch(ret)
{
case -://
break;
case :
case :
n.len += ret;
//如果未访问,保存花销;如果已经访问,保存花销最少。
if (mask[n.x][n.y] == - || n.len<mask[n.x][n.y])
{
mask[n.x][n.y] = n.len;//已经访问且保存的是最小花销
q.push(n);
}
break;
}
} }
}
int tryXY(int x,int y)
{
int ret;
//越界或遇到墙
if (!(x>= && x<w && y>= && y<h) || (Map[x][y] == '#'))
ret = -;
//road or angel
if (Map[x][y] == '.')
ret = ;
//guard
if (Map[x][y] == 'x')
ret = ;
return ret;
}

然而这个代码还有一些不足~~

1、82行代码之后应该判断是否到了目标点,达到目标则return,此时就是花销最少的路径,而不需要全部遍历结束;

2、96行的代码中“<”判断是多余的,因为如果之前已经访问过了,那么现在的一定比之前的路径长;

Code 2:

 #include<iostream>
#include<cstdio>
#include<queue>
using namespace std; //定义结点结构体
typedef struct{
int x;
int y;
int len;
}node;
//定义全局变量
#define M 202
char Map[M][M]; //地图
int visited[M][M]; //地图访问标识
queue<node> q; //队列,在bfs中用到
int bx,by,ex,ey,w,h;//起点、终点、地图宽、地图高
int step[][] = {
,-, //move up
,, //move right
,, //move down
-, //move left
}; void readMap(int m,int n); //读取地图
void bfs(); //bfs搜索路径
int costXY(int x,int y); //尝试x,y是否可行 void main(){
while(scanf("%d %d",&w,&h) == ){
readMap(w,h);
bfs();
if(visited[ex][ey]!=-){
cout<<visited[ex][ey]<<endl;
}else{
cout<<"Poor ANGEL has to stay in the prison all his life."<<endl;
}
}
}
void readMap(int m,int n){
int i,j;
for(i=;i<m;i++){
for(j=;j<n;j++){
cin>>Map[i][j];
visited[i][j] = -;//-1表示未访问
if(Map[i][j] == 'r'){//store the start point
Map[i][j] = '.';
bx = i;
by = j;
}
if(Map[i][j] == 'a'){//store the end point
Map[i][j] = '.';
ex = i;
ey = j;
}
}
}
} void bfs(){
node n,m;//m is queue head, n is a copied m for test;
int ret;
//save start point into the queue
m.x = bx;
m.y = by;
m.len = ;
visited[bx][by] = ;
q.push(m);
//bfs
while(q.size()){
//get the head point
m = q.front();
q.pop();
//if arrive end point return
if(m.x == ex && m.y == ey){
visited[ex][ey] = m.len;
return ;
}
//test node m
for(int i=;i<;i++){
n.x = m.x + step[i][];
n.y = m.y + step[i][];
n.len = m.len + ;
ret = costXY(n.x,n.y);
switch(ret){
case -:
break;
case :
case :
n.len += ret;
//if first time visit, save the cost
//if has been visited, save the minimum cost
if(visited[n.x][n.y] == -){
visited[n.x][n.y] = n.len;
q.push(n);
}
break;
}
}
}
} int costXY(int x,int y){
int ret;
//out of map or a wall
if(!(x>= && x<=w && y>= && y<=h) || Map[x][y] == '#'){
ret = -;
}
//road or angel
if(Map[x][y] == '.'){
ret = ;
}
//guard, need one more unit time
if(Map[x][y] == 'x'){
ret = ;
}
return ret;
}

6.2 HDOJ1372 Knight Moves

Description:

A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.
Your
job is to write a program that takes two squares a and b as input and
then determines the number of knight moves on a shortest route from a to
b.

Input:

The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.

Output:

For each test case, print one line saying "To get from xx to yy takes n knight moves.".

Sample Input:

 e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6

Sample Output:

 To get from e2 to e4 takes  knight moves.
To get from a1 to b2 takes knight moves.
To get from b2 to c3 takes knight moves.
To get from a1 to h8 takes knight moves.
To get from a1 to h7 takes knight moves.
To get from h8 to a1 takes knight moves.
To get from b1 to c3 takes knight moves.
To get from f6 to f6 takes knight moves.

Code:

 #include<iostream>
#include<cstdio>
#include<queue>
using namespace std; //定义node结构体
typedef struct{
int x,y,len;
}node;
//八个方向
int step[][] = {
-,-, //left2-up1
-,-, //left1-up2
,-, //right1-up2
,-, //right2-up1
,, //right2-down1
,, //right2-down2
-,, //left1-down2
-, //left2-down1
};
#define M 10
int Map[M][M];//chessboard
int bx,by,ex,ey;//begin point,end point
char a[],b[]; void bfs(int x,int y); void main(){
while(scanf("%s%s",a,b)!=EOF){
bx = a[]-'a'+; //the range of index is from 1 to 8
by = a[]-''; //the range of index is from 1 to 8
ex = b[]-'a'+; //the range of index is from 1 to 8
ey = b[]-''; //the range of index is from 1 to 8
bfs(bx,by);
}
return ;
} void bfs(int x,int y){
node t,p;
queue<node> q;
//BFS Step1:push first node t into queue q
t.x = x;
t.y = y;
t.len = ;
q.push(t);
//while(!q.empty())
while(q.size()){
//BFS Step2:get the head of queue
t = q.front();
q.pop();
//BFS Step3:arrive the end point,return. first time arriving is the minimum.
if(t.x == ex && t.y == ey){
printf("To get from %s to %s takes %d knight moves.\n",a,b,t.num);
return;
}
//BFS Step4:push the next steps into queue q
for(int i=;i<;i++){
node next;
next.x = t.x + step[i][];
next.y = t.y + step[i][];
//no out of range and not been visited
if(!(next.x> && next.x< && next.y> && next.y<) && !Map[next.x][next.y]){
next.len = t.len+;
q.push(next);
}
}
}
}

ZH奶酪:【数据结构与算法】搜索之BFS的更多相关文章

  1. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  2. 数据结构和算法总结(一):广度优先搜索BFS和深度优先搜索DFS

    前言 这几天复习图论算法,觉得BFS和DFS挺重要的,而且应用比较多,故记录一下. 广度优先搜索 有一个有向图如图a 图a 广度优先搜索的策略是: 从起始点开始遍历其邻接的节点,由此向外不断扩散. 1 ...

  3. 算法与数据结构基础 - 广度优先搜索(BFS)

    BFS基础 广度优先搜索(Breadth First Search)用于按离始节点距离.由近到远渐次访问图的节点,可视化BFS 通常使用队列(queue)结构模拟BFS过程,关于queue见:算法与数 ...

  4. C语言数据结构与算法之深度、广度优先搜索

    一.深度优先搜索(Depth-First-Search 简称:DFS) 1.1 遍历过程: (1)从图中某个顶点v出发,访问v. (2)找出刚才第一个被顶点访问的邻接点.访问该顶点.以这个顶点为新的顶 ...

  5. 算法与数据结构基础 - 深度优先搜索(DFS)

    DFS基础 深度优先搜索(Depth First Search)是一种搜索思路,相比广度优先搜索(BFS),DFS对每一个分枝路径深入到不能再深入为止,其应用于树/图的遍历.嵌套关系处理.回溯等,可以 ...

  6. 【数据结构与算法笔记04】对图搜索策略的一些思考(包括DFS和BFS)

    图搜索策略 这里的"图搜索策略"应该怎么理解呢? 首先,是"图搜索",所谓图无非就是由节点和边组成的,那么图搜索也就是将这个图中所有的节点和边都访问一遍. 其次 ...

  7. 0算法基础学算法 搜索篇第二讲 BFS广度优先搜索的思想

    dfs前置知识: 递归链接:0基础算法基础学算法 第六弹 递归 - 球君 - 博客园 (cnblogs.com) dfs深度优先搜索:0基础学算法 搜索篇第一讲 深度优先搜索 - 球君 - 博客园 ( ...

  8. 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/19617187 图的存储结构 本文的重点在于图的深度优先搜索(DFS)和广度优先搜索(BFS ...

  9. [转]MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  10. 数据结构与算法 Big O 备忘录与现实

    不论今天的计算机技术变化,新技术的出现,所有都是来自数据结构与算法基础.我们需要温故而知新.        算法.架构.策略.机器学习之间的关系.在过往和技术人员交流时,很多人对算法和架构之间的关系感 ...

随机推荐

  1. 使用 Nexus 搭建私服仓库时我犯的一个小错误

    私服搭建好,啥都配置好了,纳闷的是 Repositories 中的 group 为何总是空值?我还反反复复删了又重建,结果还是一样,不经意间再看 Configuration 选项卡的内容,发现左右两个 ...

  2. Express应用程序目录结构

    1.Node安装与使用 网上有很多Node的安装教程,可以做参考 2.MongoDB的安装与使用 MongoDB安装也有很多教程,可以去网上找找 3.初始化一个express项目 使用express框 ...

  3. Shell脚本里的双冒号是什么意思

    这个是代码开发风格,其实也就是一个函数名,相当于下划线分割,但改读成包名之后就意义不一样.这个是根据Google的Shell开发规范进行定义的. 参考: https://google.github.i ...

  4. FastBoot BootLoader Recovery 模式解释

    理论上,所有的Android设备都存在着Fastboot/Bootloader模式,不过,由于Android操作系统的开源特性,各厂商的对 自家的相关Android设备都有着各自不同的Fastboot ...

  5. jquery实现回车键触发事件

    键盘事件有3: keydown,keypress,keyup,分别是按下,按着没上抬,上抬键盘 . 正确代码为: $(document).keyup(function(event){ if(event ...

  6. memcached-session-manager配置

    原文地址: http://chenzhou123520.iteye.com/blog/1650212 声明:本篇文章是根据memcached-session-manager官方配置方法wiki页面翻译 ...

  7. Extjs DateField onchange

    1 开发思路: 在日期值变化的事件中获得选择后的日期值,传给后台,然后从后台加载相应的数据 2 问题:在查看extjs2.2 的api的官方说明文档,文档对datefield组件的change事件说明 ...

  8. 精选 5 个漂亮的 CSS3 图片滑过特效

    这篇文章将为大家分享5款漂亮的CSS3图片滑过特效,比如滑过后显示图片的详细文字介绍,又比如滑过后对图片进行淡入淡出的效果等等.让我们一起来看看,喜欢的朋友赶紧收藏. 1.非常酷的CSS3图片说明效果 ...

  9. TOMCAT6热部署配置

    在J2EE开发过程中,经常需要在启动tomcat后修改java类文件,tomcat默认会自动加载修改的类,但这只是重新启动整个项目换句话说就是自动帮我们重启tomcat,这样就浪费了大量的时间在等等t ...

  10. ubuntu MySQL安装和设置

    1. apt-get install mysql-server 2. apt-get isntall mysql-client 修改 /etc/mysql/my.cnf #bind-address   ...