广度优选搜索(bfs)
BFS大致思路:
1.首先创建一个visit[ ]数组和一个队列q,分别用来判断该位置是否已经访问过及让未访问过的点入队;
2.初始化visit[ ]数组,清空q队列;
3.让起点start入队,并使该点的visit置1;
4.while(!q.empty()){…}执行搜索操作,
-
a.取出队头元素后使队头元素出队,判断该元素是否为目标到达点;
-
b.如果是目标点,就返回结果(一般是最短时间、最短路径);
-
c.如果不是目标点,就继续访问与其相邻的位置点,将可走的相邻的位置点 入队,并更新visit[ ]数组;
这里放一道来自牛客的例题
例题的AC代码:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<b;i++)
#define T int t ;cin >> t;while(t--)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;
char mp[40][40];
int coutt[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
int si,sj;
int ei,ej;
int n,m;
int minn=INF;
int dis[40][40];
int a[40][40];
struct node{
int x,y ;
};
inline bool check(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m;
}
void bfs() //核心代码
{
queue<node>q ;
memset(dis,INF,sizeof(dis));
q.push(node{si,sj}) ; //将起点压缩进入队列
dis[si][sj]=0; //dis数组表示起点到目标位置的距离
while(!q.empty())
{
node xx = q.front() ; //xx是指的上一个位置
q.pop() ; //将第一个位置弹出
if(xx.x==ei&&xx.y==ej) //如果到达目的地
{
minn=min(minn,dis[xx.x][xx.y]); // 选出到达终点的最优解
continue;
}
for(int i=0; i<4; i++) //查看四处方向
{
int t1=xx.x+coutt[i][0];
int t2=xx.y+coutt[i][1];
if(check(t1,t2)) //确认下一步是否在方阵之中
{
if(dis[t1][t2]>dis[xx.x][xx.y]+a[t1][t2])
{
dis[t1][t2]=dis[xx.x][xx.y]+a[t1][t2];
q.push(node{t1,t2}); //将下一个点放入队列
}
}
}
}
}
int main()
{
scanf("%d %d ",&n,&m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf(" %c",&mp[i][j]);
if(mp[i][j]=='S') //标记起点
{
si=i;
sj=j;
continue;
}
if(mp[i][j]=='E') /标记终点
{
ei=i;
ej=j;
continue;
}
if(mp[i][j]=='A'||mp[i][j]=='B'||mp[i][j]=='C')
{
a[i][j]=100;
}
else
a[i][j]=mp[i][j]-'0';
}
}
bfs();
printf("%d\n",minn);
return 0;
}
下面,我再整理一个bfs的变式的例题:
洛谷:P1443 马的遍历
这是一道裸的bfs模板题目,也是用队列写的,简单易懂。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<b;i++)
#define T int t ;cin >> t;while(t--)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 405;
ll n , m , x, y ;
ll dis[maxn][maxn] ;
ll vis[maxn][maxn] ;
ll xx[8] = {2,2,1,1,-2,-2,-1,-1} ; //注意,马的走路的方式不同于其他题目,马是八面玲珑
ll yy[8] = {1,-1,2,-2,1,-1,2,-2} ; //所以有八个方向
inline bool check(ll a ,ll b){ //确保下一个点在期盼的范围内
return a>0&&a<=n&&b>0&&b<=m ;
}
struct node{
ll x,y ,path;
};
void bfs(ll x , ll y){
dis[x][y] = 0 ; //起点到起点的长度为0
queue<node> q ;
q.push(node{x,y,0}) ; //将起点压入队列中
while(!q.empty()){
node tmp = q.front() ;
q.pop() ;
for(int i = 0 ; i < 8 ; i++){
ll aa = tmp.x +xx[i] ;
ll bb = tmp.y +yy[i] ;
if(check(aa,bb)&&dis[aa][bb]==-1){
dis[aa][bb] = tmp.path + 1 ;
q.push(node{aa,bb,dis[aa][bb]}) ;
}
}
}
}
int main()
{
cin >> n >> m >> x >> y ;;
memset(dis,-1,sizeof(dis)) ;
bfs(x, y) ;
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= m ;j++){
printf("%-5lld",dis[i][j]) ; //左对齐,宽5格 这里被卡了一次...
}
cout << endl ;
}
return 0 ;
}