BFS模板(邻接矩阵版本)
BFS的大体结构:
一、预处理:
1:首先,需要定义一个:用来表示单位结点的struct结构体
思考一下,为了表示某个点上的状态,我需要记录什么?
——首先肯定有位置(思考思考,这里位置使用二维坐标表示,还是用一维坐标表示??)
2:考虑一下,需不需要一个vis数组,来避免重复搜索?
3:定义一个,约束条件检验函数 (is_ok),主要判断:是否走到图边界,是否已经走过了
二、bfs主函数(伪代码):
void bfs (传入起始结点的位置)
{
定义队列 q
配置、压入首节点,并把首节点pop出队列
访问标记
while(!q.empty())
{
取出队列头结点,作为本次处理的点对象。
检验:此点是否已经达到目标状态,如果达到,直接结束bfs。(记住:检验在扩展之前)
如果没达到,开始从这个点发散扩展,并将扩展找到的所有合法结点,压入队列末尾。
}
return ;
}
代码(邻接矩阵):
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=100; int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量 bool vis[maxn][maxn]; // 访问标记。我的习惯上,统一放在外面,不放在结构体里面。 struct node // BFS 队列中,每一个单位结点的,状态数据结构。 { int x,y; // 坐标位置 //这里注意,并不是每道题的单位结点,都用x和y两个数据来标记位置。 //有些题,一维就足以标记自己的位置了 (比如,专题6 1004)
int dpth; // 记录该节点的深度 }; //相当于是,把结点打包为一个整体的结构体,压入队列。 //bfs是以队列里的每个元素为单位,记录自己的dpth
//实际上,用二维坐标表示点的位置,常见于:题目给的输入,天然就是一张图,自带双维点坐标(比如那种“迷宫格”一样的题,专题6绝大部分题)
//而用一维表示图中点的位置(也就是说,只用标号,表示某个点),常见于:题目给的输入,并不是图,图是自己构建的(比如专题6的1004)
node a[maxn]; bool is_ok(node s) // 约束条件检验 { if(!vis[s.x][s.y] && ...) return 1; else return 0; } void bfs(int x,int y)//传入:本次bfs搜索的,起始点。(从一个点开始,向外扩展) { queue <node> q; // BFS 队列 node sta; //配置起始点 sta.dpth=0; sta.x=x; sta.y=y; q.push(sta); // 把起始点入队 vis[sta.x][sta.y]=1; // 访问标记 while(!q.empty()) { node pro=q.front(); // 取队首元素为本次待处理元素,作为后续扩展的起点 q.pop(); if(pro==G) //首先判断:本次待处理元素(现在站的这个位置),是否已经满足“目标状态” //请注意,在此节点被扩展之前,就进行这个判断。 { ...... return; } //找到答案,直接输出,结束程序。因为: //是广度优先搜索,越往后step越大,所以最先找到的step就是最小的那个。 for(int i=0;i<4;i++) //扩展,遍历地寻找每一个相邻点。 { node tmp; //生成下一个状态 tmp.x=pro.x+dir[i][0]; tmp.y=pro.y+dir[i][1]; tmp.dpth=pro.dpth+1; if(is_ok(tmp)) // 如果状态满足约束条件,则入队 { q.push(tmp); vis[tmp.x][tmp.y]=1; //访问标记,标记为已经走过,走过的点不再重复走。 //请记住:每次,只要你把某个节点加入队列了,都要标记该节点的vis。 } } } return; } int main() { ...... //主函数里面,主要搞清楚,是只从一个节点开始就可以了,还是要循环地从每个结点,遍历开始。 //也就是说,是一个bfs就够了,还是要多个bfs。 return 0; }
再说说邻接表:
至于邻接表的bfs,其实和邻接矩阵基本一样,要点就在于:
邻接表如何存储图,又如何调出图数据
在bfs里,也就是说:给定一个点,在邻接表中,如何找到它的所有邻接点??
这再简单不过了。
1:邻接图的存储,可以用vector数组,也可以用set数组,用set可以避免重复存储相同结点,二者酌情选用。
存储的都是:与这个点相连的,所有节点,的编号(实质上,存储的是,能够完整表示某个节点的信息。通过这里面信息,要能找出所需点才行。)
(例如: vector<int> mp[20] , 或者set<int> mp[20})
(或者map<node> mp[maxn]————当节点信息不能一维表示的时候,可用map,从某个node映射到与他相良的所有node)
2:找到某个点x的所有邻接点,只需要遍历容器mp[x]即可。
顺便补充,set的遍历:
for(auto i:mp[x])
{
if(is_correct(i))
{
q.push(i);
vis[i]=1;
}
}
简而言之,邻接表的bfs和邻接矩阵基本一样,只需要在:主函数(读入图的时候) 和 当前pro结点扩张的时候(遍历某个点的邻接点的时候) 变一下,即可。
另外,只在每个点用一维(也就是一个参数,比如点标号)表示的时候,邻接表才好用。
如果是那种“迷宫格”的题,邻接表似乎就不太好用。
(邻接表bfs做题链接:专题6 1004 邻接表版本)
浙公网安备 33010602011771号