广度优先搜索总结

广度优先搜索是对无向图以逻辑上的树的形式从根节点开始进行的逐层遍历。

当题目所求为路径某属性最小的解时适用广度优先搜索,因为如果能使逻辑上的树的层数和所求的最小的属性严格一致,逐层遍历到终点时必然为其属性最小值。

算法实现:基于(优先)队列先进先出的特性,实现优先遍历上层节点,通过标记数组保证访问过的点不被多次访问。

将根节点入队,在while(!q.empty())循环中将队首取出,并建立其子节点信息,如果子节点是合法的就入队并标记,直到找到答案或队列为空表示未找到。

注意问题:1、初始化标记数组为0(当用普通队列实现优先队列功能时,标记数组初始化为INF),使用前清空队列。

     2、设置标记在入队处,这样能保证被访问过的节点不再被访问。

     3、注意边界处理,边界判断在对地图判断之前,防止下标越界。

带注释模板:

HDU-2717

 1 #include <iostream>
 2 #include <queue>
 3 #include <string.h>
 4 using namespace std;
 5 int n,m;//n是初始位置,m是终点
 6 int vis[200005];//用来记录是否访问过,未访问为0访问过就置1
 7 struct Node
 8 {
 9     int pos;//记录当前位置
10     int time;//记录当前用时
11 };
12 queue <Node> q;
13 bool ok(Node dep)
14 {
15     if(dep.pos<0||dep.pos>100000)//这道题目最远是100000,所以超过这个就可以不考虑了
16         return false;
17     if(vis[dep.pos]==1)//如果被访问过就不去
18         return false;
19     vis[dep.pos]=1;//如果可以走,就把它标记一下,表示我走过了,防止再走
20     return true;
21 }
22 int bfs()
23 {
24     while(!q.empty())//如果队列非空就循环,直到找到终点
25     {
26         Node now,next;//新建两个节点,一个是当前节点,一个是下一个位置的节点
27         now=q.front();//把队列第一个元素传给now
28         q.pop();//删除第一个元素,根据队列特性,后续元素会自动往前推
29         if(now.pos==m)
30         {
31             return now.time;//如果到达终点,便返回当前时间,函数结束
32         }
33         next=now;//设置next的信息,分别是+1,*2-,-1,时间在now基础上+1
34         next.pos++;
35         next.time++;
36         if(ok(next))//ok函数判断这个点能不能走
37             q.push(next);//如果可以就入队
38         next=now;
39         next.pos*=2;
40         next.time++;
41         if(ok(next))
42             q.push(next);
43         next=now;
44         next.pos--;
45         next.time++;
46         if(ok(next))
47             q.push(next);
48     }
49 }
50 int main()
51 {
52     while(cin>>n>>m)
53     {
54         memset(vis,0,sizeof(vis));
55         while(!q.empty())
56             q.pop();
57         Node st;//建立起点信息
58         st.pos=n;
59         st.time=0;
60         vis[n]=1;
61         q.push(st);//入队
62         cout<<bfs()<<endl;
63     }
64     return 0;
65 }

BFS相关题目(补充中...):

HDU-2612  Find a way

一对好基友要在KCF面基,找出总用时最少的KCF地点,只要分别以两个人为起点去找出所有的KCF并记录到每个KCF的最短时间,然后求下最小值就行。

注意这里的总用时是两者用时之和,且不像一般广搜搜到就结束,这里需要把所有KCF搜完再结束。

#include <iostream>
#include <queue>
#include <string.h>
#include <stdio.h>
using namespace std;
struct Node
{
    int x,y;
    int time;
};
queue <Node> q;
int n,m,cot;
char _map[215][215];
int vis[215][215];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int ktime[215][215];
bool ok(Node now)
{
    if(now.x<=0||now.x>m||now.y<=0||now.y>n)
        return false;
    if(vis[now.y][now.x]==1)
        return false;
    if(_map[now.y][now.x]==‘#‘)
        return false;
    return true;
}
void bfs(int flag,int ord)
{
    Node now,next;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        if(_map[now.y][now.x]==‘@‘)
        {
            ktime[now.y][now.x]+=now.time;
        }
        for(int i=0;i<4;i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            next.time=now.time+1;
            if(ok(next))
            {
                vis[next.y][next.x]=1;
                q.push(next);
            }
        }
    }
}
int main(int argc, const char * argv[]) {
    while(cin>>n>>m)
    {
        while(!q.empty())
            q.pop();
        memset(_map,‘0‘,sizeof(_map));
        memset(ktime,0,sizeof(ktime));
        memset(vis,0,sizeof(0));
        int i,j;
        Node M,Y;
        cot=0;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                cin>>_map[i][j];
                if(_map[i][j]==‘Y‘)
                {
                    Y.x=j;
                    Y.y=i;
                    Y.time=0;
                }
                if(_map[i][j]==‘M‘)
                {
                    M.x=j;
                    M.y=i;
                    M.time=0;
                }
                if(_map[i][j]==‘#‘)
                    cot++;
            }
        }
        while(!q.empty())
            q.pop();
        memset(vis,0,sizeof(vis));
        vis[Y.y][Y.x]=1;
        q.push(Y);
        bfs(0,0);
        while(!q.empty())
            q.pop();
        memset(vis,0,sizeof(vis));
        vis[M.y][M.x]=1;
        q.push(M);
        bfs(1,0);
        int _min=11111111;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                if(_map[i][j]==‘@‘&&ktime[i][j])
                {
                    if(_min>=ktime[i][j])
                        _min=ktime[i][j];
                }
            }
        }
        cout<<_min*11<<endl;
    }
    return 0;
}

HDU-1548 A strange lift

电梯有向上、向下一层、到达Ki层的功能(请给我一台),简单遍历一下找到终点就行,注意下边界。

#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
int n,a,b,num[205],mint;
int vis[205];
struct node
{
    int pos,time;
};
queue <node> q;
bool ok(node now)
{
    if(now.pos<=0||now.pos>n)
        return false;
    if(vis[now.pos]==1)
        return false;
    return true;
}
void bfs()
{
    while(!q.empty())
    {
        node now,next;
        now=q.front();
        q.pop();
        vis[now.pos]=1;
        if(now.pos==b)
        {
            mint=now.time;
            return;
        }
        next=now;
        next.pos+=num[now.pos];
        next.time++;
        if(next.pos==b)
        {
            mint=next.time;
            return;
        }
        if(ok(next))
            q.push(next);
        next=now;
        next.pos-=num[now.pos];
        next.time++;
        if(next.pos==b)
        {
            mint=next.time;
            return;
        }
        if(ok(next))
            q.push(next);
    }
}
int main()
{
    while(cin>>n)
    {
        if(n==0)
        break;
        cin>>a>>b;
        mint=-1;
        memset(num,0,sizeof(num));
        memset(vis,0,sizeof(vis));
        while(!q.empty())
            q.pop();
        for(int i=1;i<=n;i++)
            cin>>num[i];
        node st;
        st.pos=a;
        st.time=0;
        q.push(st);
        bfs();
        cout<<mint<<endl;
    }
    return 0;
}

HDU-1253 胜利大逃亡

三维空间的搜索,判断条件比较多,注意不要写错了。据说终点可能是不能走的,可以在主函数单独判断一下,省的搜索了,不过要是测试数据不给面子,优化不了多少时间。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <queue>
 5 #include <cmath>
 6 using namespace std;
 7 int _map[55][55][55];
 8 int vis[55][55][55];
 9 int dir[6][3]={{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}};
10 int mintime,time;
11 int n,m,s;
12 struct block
13 {
14     int x,y,z;
15     int time;
16 };
17 bool ok(block now)
18 {
19     if(abs(now.x-s+1)+abs(now.y-m+1)+abs(now.z-n+1)+now.time>time)
20         return false;
21     if(vis[now.z][now.y][now.x]==1)
22         return false;
23     if(_map[now.z][now.y][now.x]==1)
24         return false;
25     if(now.y<0||now.y>=m||now.z<0||now.z>=n||now.x<0||now.x>=s)
26         return false;
27     return true;
28 }
29 queue<block> q;
30 int bfs()
31 {
32     block now;
33     block next;
34     while(!q.empty())
35     {
36         now=q.front();
37         q.pop();
38         if(now.z==(n-1)&&now.y==(m-1)&&now.x==(s-1)&&now.time<=time)
39             return now.time;
40         for(int i=0;i<6;i++)
41         {
42             next=now;
43             next.x+=dir[i][0];
44             next.y+=dir[i][1];
45             next.z+=dir[i][2];
46             if(ok(next))
47             {
48                 next.time++;
49                 vis[next.z][next.y][next.x]=1;
50                 q.push(next);
51             }
52         }
53     }
54     return -1;
55 }
56
57 int main()
58 {
59     int t;
60     cin>>t;
61     while(t--)
62     {
63         memset(_map,0,sizeof(_map));
64         memset(vis,0,sizeof(vis));
65         while(!q.empty())
66             q.pop();
67         scanf("%d %d %d %d",&n,&m,&s,&time);
68         int i,j,k;
69         for(i=0;i<n;i++)
70         {
71             for(j=0;j<m;j++)
72             {
73                 for(k=0;k<s;k++)
74                 {
75                     scanf("%d",&_map[i][j][k]);
76                 }
77             }
78         }
79         if(_map[n-1][m-1][s-1]==1)
80         {
81             printf("-1\n");
82             continue;
83         }
84         block st;
85         st.x=st.y=st.z=st.time=0;
86         q.push(st);
87         mintime=bfs();
88         printf("%d\n",mintime);
89     }
90     return 0;
91 }

未完待续...(若有错误、不足之处望谅解并指出)

时间: 2024-11-03 21:14:10

广度优先搜索总结的相关文章

无向图的深度优先与广度优先搜索代码实现

图采用了邻接表的形式储存. 带不带权都无所谓的 深度优先搜索 Depth First Search 道理和树的先序遍历差不多,把将要访问的点入栈,然后从栈里取点进行访问. 由于这只是类中的一个成员函数,有些被调用的函数的具体代码将会在文章最后补上 ,但是函数功能看注释就好了 1 //深度优先 2 void GraphAdjacencyListWeight::DFSAdvanced(int StartVertex) { 3 int *visited = new int[VertexNumber];

SDUT 2141 【TEST】数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历

数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Description 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列.(同一个结点的同层邻接点,节点编号小的优先遍历) Input 输入第一行为整数n(0< n <100),表示数据的组数.对于每组数据,第一行是三个整数k,m,t(0<

数据结构实验之图论二:基于邻接表的广度优先搜索遍历

数据结构实验之图论二:基于邻接表的广度优先搜索遍历 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列.(同一个结点的同层邻接点,节点编号小的优先遍历) 输入 输入第一行为整数n(0< n <100),表示数据的组数. 对于每组数据,第一行是三个整数k,m,t(0<k<100,0<m<(k-1)*k/2,

图算法系列-深度优先搜索与广度优先搜索

2.深度优先搜索 为了访问一个顶点,我们将它标记为已经访问过,然后递归的访问所有与子邻接的并且尚未标记的顶点,这就是深度优先搜索(DFS),DFS常用于解决路径问题. 比如下面的连通图,我们从顶点0开始对图进行探索 下面这个图显示了DFS处理时的递归调用树. DFS可以解决的问题:1)环检测:一个图中有环吗?该图是森林吗?2)简单路径:给定两个顶点,是否存在一条连接他们的路径3)简单连通性:无论何时使用DFS,都可以在线性时间内确定一个图是否连通4)顶点搜索:在给定顶点所在的同一个连通分量中有多

图的遍历(深度优先与广度优先搜索两种方案)

1.图的遍历--深度优先搜索 import java.util.Scanner ; public class Map{ static int n ; static int m ; static int[] book ; static int[][] e ; public static void mapDfs(int cur){ //深度优先搜索思想核心: System.out.print(cur + " ") ; for (int i=1;i<=n;i++) { if (e[cu

矩阵图中的广度优先搜索

经常会有类似的题目,如迷宫问题,在一个矩阵图中给定出发点和目标点,每次只能上下左右移动,求到目标点的最短走法,或者说是一共有多少种走法. 思路其实很简单,深搜.广搜.相对比较而言,广度优先搜索更加实用于求最短的走法(步数) 在矩阵图中的广搜需要注意一下几点. 1.确定每步的走法:不同题的走法可能不同,每次搜索时将走法保存在数组中. 2.确定初始状态 往往注意刚开始得起点(i,j)必须把MAP(i,j)改变为 -1(或者其他的),栈中第一个元素即为初始状态 3.保存状态.这点很重要.需要用数组或者

地牢逃脱(BFS(广度优先搜索))

题目描述 给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (x0 , y0 ) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一些指定的步长遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上.地牢的出口可能在任意某个可以通行的位置上.牛牛想知道最坏情况下,他需要多少步才可以离开这个地牢. 输入描述: 每个输入包含 1 个测试用例.每个测试用例的第一行包含两个整数 n 和 m(1 <= n, m <= 50),表示

图的广度优先搜索(BFS)

把以前写过的图的广度优先搜索分享给大家(C语言版) 1 #include<stdio.h> 2 #include<stdlib.h> 3 #define MAX_VERTEX_NUM 20 4 #define MAXQSIZE 100 5 #define OK 1 6 typedef char VertexType; 7 typedef int QElemType; 8 9 typedef struct ArcNode//边结点 10 { 11 int adjvex; 12 str

SDUT 2142 【TEST】数据结构实验之图论二:基于邻接表的广度优先搜索遍历

数据结构实验之图论二:基于邻接表的广度优先搜索遍历 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Description 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列.(同一个结点的同层邻接点,节点编号小的优先遍历) Input 输入第一行为整数n(0< n <100),表示数据的组数.对于每组数据,第一行是三个整数k,m,t(0<

图的遍历之 深度优先搜索和广度优先搜索

本章会先对图的深度优先搜索和广度优先搜索进行介绍,然后再给出C/C++/Java的实现. 目录 1. 深度优先搜索的图文介绍 1.1 深度优先搜索介绍 1.2 深度优先搜索图解 2. 广度优先搜索的图文介绍 2.1 广度优先搜索介绍 2.2 广度优先搜索图解 3. 搜索算法的源码 深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似. 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然