BFS,不得不爱的算法

宽度有限搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一。

Dijkstra单源最短路径算法和Prim最小生成树算法都采用了宽度优先搜索类似的思想。
BFS(Breadth First Search)属于一种盲目搜寻法,目的是系统的展开并检查图中的所有节点,以找寻结果。

dfs=栈,压栈,出栈;(栈可以保存路径)
bfs=队列,入队列,出队列;(队列可以计算路径长度)

bfs是按一层一层来访问,适合求最短路径的步数,

深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:
1、把根节点压入栈中。
2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。

int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}
 
void dfs(int step)
{
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件
               标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)
        }
}   
例题 迷宫问题:

输入
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)

#include <iostream> 
#include <algorithm> 
#include <stack> 
#include <vector> 
using namespace std; 
struct point{
	int x,y;
}p;
int main(){ 
    int N, M; 
    while(cin >> N >> M){ 
		vector<vector<int> > maze(N,vector<int>(M));
		vector<vector<int> > vis(N,vector<int>(M));
        for(int i =0; i<N; i++){ 
            for(int j =0; j<M; j++){ 
                cin >> maze[i][j]; 
				vis[i][j]=0;
            } 
        } 
        int dir[4][2] = { 1,0,-1,0,0,1,0,-1};//点的四个方向
        bool flag =0; //是否走完 
        stack<point> stk; 
		point s={0,0};
        stk.push(s); 
        vis[0][0] =1; 
        while(!flag){   //深度优先搜索思想,往该点四个方向探查,若有则从这点继续探寻,若没有则回溯到上一个点
            p = stk.top();   //回退路径的点 
            stk.pop(); 
            int i = p.x, j= p.y; 
            for(int k =0; k <4;k++){  //对四个方向进行探查 
                int dx = i + dir[k][0]; 
                int dy = j + dir[k][1]; 
				point temp={dx,dy};
                if(dx == N-1&&dy == M-1){ //到达终点 
                    stk.push(temp); 
                    flag =true; 
                    break; 
                } 
                if(dx>=0&& dx<=N-1&& dy>=0&& dy<=M-1&& maze[dx][dy] ==0&& vis[dx][dy] ==0)
				{  //未被访问过且有路径 
                    stk.push(temp); 
                    vis[dx][dy] =1; 
                    i = dx;     //从该点继续探查 
                    j = dy; 
                    k=-1; 
                } 
            } 
        } 
        stack<point> outputStk;  //把栈的先后顺序换一下输出 
        while(!stk.empty()){ 
            outputStk.push(stk.top()); 
            stk.pop(); 
        } 
		outputStk.push(s);
        while(!outputStk.empty()){ 
            point p = outputStk.top(); 
            outputStk.pop(); 
            cout <<"("<<p.x<<","<<p.y<<")"<< endl; 
        } 
    } 
    return 0; 
} 

广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。


#include<iostream>
#include<string>
#include<queue>
using namespace std;
char a[1010][1010];//记录整个图形的
int vis[1010][1010];//用来标记的走没走过
struct Point{
     int x, y;
}tmp1, tmp2;
int mt[4][2] = {1,0,-1,0,0,1,0,-1};//移动的四个方向
queue<Point>q;
int main(){
    int n, i, j;
    while(~scanf("%d", &n))
	{
         for(i = 0; i < n; i++)
		 {
            scanf("%s", a[i]);
         }
         int sx, sy;
         int ex, ey;
         for(i = 0; i < n; i++){
            for(j = 0; j < n; j++){
                vis[i][j] = 0;//初始化标记
                if(a[i][j] == 'S'){//找到初始位置
                    sx = i;
                    sy = j;
                }
                else if(a[i][j] == 'E'){//终点位置
                    ex = i;
                    ey = j;
                }
            }
         }
         while(!q.empty()){//队列初始化
             q.pop();
         }
         tmp1.x = sx;
         tmp1.y = sy;
         vis[tmp1.x][tmp1.y] = 1;//首先压入起始位置
         q.push(tmp1);
         int flag = 0;
         while(!q.empty()){
            tmp1 = q.front();
            q.pop();
            for(i = 0; i < 4; i++)
			{
                tmp2.x = tmp1.x + mt[i][0];//引动的方向:横坐标向右移一位  x+1
                tmp2.y = tmp1.y + mt[i][1];
                if(tmp2.x >=0 && tmp2.x < n && tmp2.y >= 0 && tmp2.y < n && !vis[tmp2.x][tmp2.y] && a[tmp2.x][tmp2.y] != '#')
				{
                        //判断条件
                    vis[tmp2.x][tmp2.y] = vis[tmp1.x][tmp1.y] + 1;//原来的位置加一
                    q.push(tmp2);
                }
            }
            if(vis[ex][ey]){//如果到达终点就标记一下,表示能到达终点
                flag = 1;
                break;
            }
         }
         if(flag)printf("%d\n", vis[ex][ey]-1);//终点位置也包括在内,所以减1
         else printf("-1\n");
    }
return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值