BFS学习总结

BFS学习总结

给你一个n*m的网格迷宫,迷宫中有些格子不能走,其他的格子都能走。然后给你起点与终点,问你从起点走到终点最少需要多少步?

上面的问题就是一个典型的BFS问题,对于这类问题来说,只要你掌握了这类问题的关键思想,其实他们都是可以用类似的思路来做的。

你可以把BFS问题想象成:从一个父亲(起点状态)生儿子(后继状态),儿子又生孙子(后继状态)的过程,只要这个家族中出生了一个满意的后代(终点状态),这个家族就不生了。

但是如果这个家族中有两个完全一样的人出生(他们的辈分不一定相同),那么后出生的人应该停止让他继续产生后代(状态去重),因为他的所有后代肯定与前面那个人的所有后代一模一样且出生时间反而更晚。

整个后代的繁殖过程是通过队列来实现的。

一般的BFS问题我是按下面步骤来做的:

         1)设计状态

对于上面的问题,我把当前人的位置以及人到该位置所花费的最小时间t,即x和y坐标(行与列坐标)与时间t作为一个有效状态。严格来说x和y才算状态属性,而t只能算状态的当前值。而我们要求的是终点状态的最小时间t值。

对于每个有效状态X,它可以继续延伸出后继状态。比如本题的X状态的后继状态就是当人在X点然后向上下左右4个方向走时所产生的后继状态(假设4个方向的格子都能走)。

对于相同的状态我们只处理一次,如果某个状态的后继状态是之前我们已经处理过的状态,那么直接抛弃这个后继状态,不入队列(想想为什么)。

2)记录同类状态最优值

就是要记录当达到任意一个同类状态(对于本题我们把坐标值相同的状态看成是同一类的)时的最优效果。比如本题,令dist[i][j]==t表示当人到达(i, j)这类状态时,所需要的最小时间t。这个最小时间就是我们要的最优效果。

3)状态剪枝

每个状态的后继状态一般都有好几个,这样我们只要做几轮出队入队操作,队列中的状态就是变成指数级别了。所以对于那些出现多次的同类状态,我们只保存一个入队列。且如果上面dist[4][5]==2(即花了2步从起点走到(4,5)点),那么当某个后继状态是(4,5,3)时,我们果断抛弃这个状态(想想为什么,其实(4,5,2)我们就可以抛弃)。

(其实通过下面的题目可以知道,有些状态需要很多元素来表示,直接导致如果用dist数组来判定重复将会定义dist为dist[][][][][][][][][][]这样,所以这时候我们采取的策略是:HASH判重+保存所有已出现的非重复状态)

4)查找目标状态

这个就是当我们在生成后继状态的时候看看是否有目标状态出现(比如坐标在终点的状态)。对于本题来说,只要出现了一个目标状态,我们直接退出即可。因为后面出现的目标状态所花的时间肯定更多(想想为什么)。

下面给出一个我写的上面问题的大致解法代码:

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=100+5;

int dx[]={-1,1,0,0};//上下左右
int dy[]={0,0,-1,1};
int n,m;
int sr,sc;//起点
int er,ec;//终点
struct Node//BFS状态
{
    int r,c;
    int dist;
    Node(){}
    Node(int r,int c,int dist):r(r),c(c),dist(dist){}
};
int mp[maxn][maxn];//1格可行,0格为障碍
int dist[maxn][maxn];//最小距离

int BFS()
{
    queue<Node> Q;
    memset(dist,-1,sizeof(dist));
    Q.push(Node(sr,sc,0));
    dist[sr][sc]=0;

    while(!Q.empty())
    {
        Node x=Q.front(); Q.pop();

        for(int dir=0;dir<4;dir++)//向4个方向走
        {
            int nr=x.r+dx[dir];
            int nc=x.c+dy[dir];
            if(nr>=1 && nr<=n && nc>=1 && nc<=m && mp[nr][nc])//不能越过网格边界且当前格可行
            {
                if(dist[nr][nc]==-1 || dist[nr][nc]>dist[x.r][x.c]+1)//状态去重
                {
                    dist[nr][nc]=dist[x.r][x.c]+1;
                    Q.push(Node(nr,nc,dist[nr][nc]));
                    if(nr==er && nc==ec) return dist[nr][nc];//到达终点
                }
            }
        }
    }
    return -1;//无法到达终点
}

int main()
{
    while(scanf("%d%d",&n,&m)==2 && n && m)
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&mp[i][j]);//1格可行,0格为障碍
            if(mp[i][j]==2)//起点
            {
                mp[i][j]=1;
                sr=i;
                sc=j;
            }
            else if(mp[i][j]==3)//终点
            {
                mp[i][j]=1;
                er=i;
                ec=j;
            }
        }

        printf("%d\n",BFS());//输出起点到终点最小距离
    }
    return 0;
}

BFS题解应用

UVA 11624 Fire!(图论BFS):解题报告!

POJ 3278 Catch That Cow(图论:BFS):解题报告!

POJ 3414 Pots(图论:BFS):解题报告!

POJ 1324 Holedox Moving(图论:BFS):解题报告!

POJ 2243 Knight Moves(BFS或DFS):解题报告!

POJ 3984 迷宫问题(BFS:迷宫最短路径且输出路径):解题报告!

POJ 1915 Knight Moves(DFS/BFS):解题报告!

POJ 1753 Flip Game(BFS+状态压缩):解题报告!

POJ 1606 Jugs(BFS:找最短路径并输出):解题报告!

POJ 1077 Eight(BFS:输出路径):解题报告!

POJ 3346 Treasure of theChimp Island(BFS):解题报告!

POJ 2046 Gap(BFS+hash判重):解题报告!

POJ 3322 Bloxorz I(BFS:求迷宫最短路径):解题报告!

POJ3221 Diamond Puzzle(BFS:最短路):解题报告!

POJ2110 Mountain Walking(BFS/DFS+二分+枚举区间):解题报告!

POJ 2920 Mine Map(BFS):解题报告!

POJ 1465 Multiple(BFS+同余剪枝):解题报告!

HDU 1728 逃离迷宫(BFS):解题报告!

HDU 1240 Asteroids!(BFS):解题报告!

HDU 2579 Dating with girls(2)(BFS):解题报告!

HDU 1226超级密码(数位BFS):解题报告!

HDU 1072 Nightmare(BFS):解题报告!

HDU 1495 非常可乐(BFS:3杯倒水):解题报告!

HDU 1430 魔板(BFS+HASH+置换):解题报告!

HDU 2612 Find a way(BFS):解题报告!

HDU 1180 诡异的楼梯(BFS:时间动态图):解题报告!

HDU 1547 Bubble Shooter(BFS):解题报告!

HDU 1312 Red and Black(简单BFS):解题报告!

HDU 1253 胜利大逃亡(简单三维BFS):解题报告!

HDU 1401 Solitaire(棋盘状态BFS):解题报告!

HDU1175 连连看(BFS):解题报告!

HDU 1242 Rescue(BFS或BFS+优先队列):解题报告!

HDU 2531 Catch him(BFS:判断是否存在路径):解题报告!

时间: 2024-10-12 22:08:53

BFS学习总结的相关文章

学习笔记:图的DFS和BFS的两种搜索办法

  在学习图结构的过程中,DFS和BFS是两种不同的遍历方式,其寻找元素具有不同的优点和缺陷. BFS被称作广度优先算法, 在遍历整个图的过程中,BFS将采用入队的方式进行,值得一提的是,这和树结构中的层序遍历有很大的相似之处. 在层序遍历中,将父亲节点入队后,在父亲节点出队后,将其儿子节点入队. 同理在图的BFS遍历中,先让BFS的首元素入队,在收元素入队后将他的儿子节点入队,放能够实现BFS搜索,他们的整体思想是一样的. 1 void TraversalGraph_BFS(LGraph Gr

数据结构学习笔记05图 (邻接矩阵 邻接表--&gt;BFS DFS)

数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边<v, w> 表示从v指向w的边(单行线) 不考虑重边和自回路 无向图:边是无向边(v, w) 有向图:边是有向边<v, w> 连通:如果从V到W存在一条(无向)路径,则称V和W是连通的 连通图(Connected Graph):如果对于图的任一两个顶点v.w∈V,v和w都是连通的,则称

ACM学习历程—HDU 5012 Dice(ACM西安网赛)(bfs)

Problem Description There are 2 special dices on the table. On each face of the dice, a distinct number was written. Consider a1.a2,a3,a4,a5,a6 to be numbers written on top face, bottom face, left face, right face, front face and back face of dice A.

【算法学习笔记】63. BFS SJTU OJ 1281 蹦蹦跳跳

典型的BFS,找到起点直接进行搜搜即可.要注意的就是层数的处理.坐标到id的转换.还有就是要尽早判断是否达到终点. 代码注释很详细,最后面两个函数是一开始写的 用抽取邻接矩阵+Dijkstra 来算的,很麻烦 头脑一热的结果.. #include <vector> #include <queue> #include <iostream> using namespace std; int map[31][31]={0}; int M,N,M1,M2; struct Poi

ACM学习历程—HDU 5025 Saving Tang Monk(广州赛区网赛)(bfs)

Problem Description <Journey to the West>(also <Monkey>) is one of the Four Great Classical Novels of Chinese literature. It was written by Wu Cheng'en during the Ming Dynasty. In this novel, Monkey King Sun Wukong, pig Zhu Bajie and Sha Wujin

ACM学习历程—Hihocoder 1233 Boxes(bfs)(2015北京网赛)

hihoCoder挑战赛12 时间限制:1000ms 单点时限:1000ms 内存限制:256MB   描述 There is a strange storehouse in PKU. In this storehouse there are n slots for boxes, forming a line. In each slot you can pile up any amount of boxes. The limitation is that you can only pile a

算法学习笔记 二叉树和图遍历—深搜 DFS 与广搜 BFS

图的深搜与广搜 马上又要秋招了,赶紧复习下基础知识.这里复习下二叉树.图的深搜与广搜.从图的遍历说起,图的遍历方法有两种:深度优先遍历(Depth First Search), 广度优先遍历(Breadth First Search),其经典应用走迷宫.N皇后.二叉树遍历等.遍历即按某种顺序访问"图"中所有的节点,顺序分为: 深度优先(优先往深处走),用的数据结构是栈, 主要是递归实现: 广度优先(优先走最近的),用的数据结构是队列,主要是迭代实现: 对于深搜,由于递归往往可以方便的利

【算法学习笔记】49.暴力穷举 BFS 剪枝 SJTU OJ 1357 相邻方案

相邻方案 Description 有一个5*5的矩阵,每个元素只可能是H或者J. 我们现在需要选择7个相邻的格子使得H的数量小于J的数量.其中,拥有公共边的两个格子可以被称为相邻的格子. 对于任意一种输入的5*5矩阵,请输出满足上述条件的方案总数. Input Format 共5行,表示矩阵情况.(每一个元素只可能是H或J) Output Format 一个整数N,代表不相同方案的总数. Input Sample HHHHH JHJHJ HHHHH HJHHJ HHHHH Output Samp

算法学习 - 图的广度优先遍历(BFS) (C++)

广度优先遍历 广度优先遍历是非经常见和普遍的一种图的遍历方法了,除了BFS还有DFS也就是深度优先遍历方法.我在我下一篇博客里面会写. 遍历过程 相信每一个看这篇博客的人,都能看懂邻接链表存储图. 不懂的人.请先学下图的存储方法.在我的之前博客里. 传送门:图表示方法 然后我们如果有一个图例如以下: 节点1->3->NULL 节点2->NULL 节点3->2->4->NULL 节点4->1->2->NULL 这样我们已经知道这是一个什么图了. 如果我们