BFS:适用于图形结构的搜索,与数据结构中的队列紧密相连。
对于这种算法主要步骤如下:
找到当前可拓展的点 ,将他放入候选队列中
每次选取候选队列的队头作为当前状态
性质:
对于广搜而言,他是一种逐层遍历的算法,所有状态按照入队的先后顺序具有层次的单调性,也就是所需的步数的单调性。如果每次拓展恰好对应一步,那么当第一个状态第一次被访问(入队)就会得到从起始状态到达该状态的最少步数。
//模板
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define MAX 0x3f3f3f3f
using namespace std;
int map[305][305];//存节点信息
int vis[305][305];//标记数组
int dir[4][2]= {-1,0, 1,0, 0,1, 0,-1};//上下左右四个方向
int end;
struct node
{
int x,y;//两点表示节点位置
int time;
} start;//入队列使用
queue<node> q;//队列,自己维护用来存储节点信息
int bfs(int x,int y)
{
memset(vis,0,sizeof(vis));
start.x=x,start.y=y,start.time=0;//将传递过来的0.0节点放入结构体
vis[x][y]=1;//标记为已搜过
q.push(start);//入队列
while(!q.empty())
{
node now=q.front();//取队头元素
q.pop();
if(map[now.x][now.y]==MAX)
{
return now.time;//如果符合条件,返回;根据题意自己写符合的条件。
}
for(int i=0; i<4; i++)//四个方向入队列
{
start.x=now.x+dir[i][0],start.y=now.y+dir[i][1];//将第一个方向的入队列
start.time=now.time+1;
if(start.x>=0&&start.y>=0&&vis[start.x][start.y]==0&&start.time<map[start.x][start.y])//判断是否越界
{
vis[start.x][start.y]=1;
q.push(start);
}
}
}
return -1;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(map,MAX,sizeof(map));
for(int j=0; j<n; j++)
{
int x,y,time;
scanf("%d%d%d",&x,&y,&time);
if(map[x][y]>time)
map[x][y]=time;
for(int i=0; i<4; i++)//自己建图过程,一般不需要自己建图
{
int cx,cy;
cx=x+dir[i][0],cy=y+dir[i][1];
if(cx>=0&&cy>=0)
if(map[cx][cy]>time)
map[cx][cy]=time;
}
}
int ans=bfs(0,0);//从00点开始广搜,根据题目要求具体定
cout<<ans<<endl;
}
}
P1162 填涂颜色
题目描述
由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n=6),涂色前和涂色后的方阵如下:
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数n(1≤n≤30)
接下来n行,由0和1组成的n×n的方阵。
方阵内只有一个闭合圈,圈内至少有一个0。
//感谢黄小U饮品指出本题数据和数据格式不一样. 已修改(输入格式)
输出格式
已经填好数字2的完整方阵。
输入输出样例
输入 #1
6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
输出 #1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
说明/提示
1≤n≤30
一句话概括题意:将联通的封闭0变为2.
//奇妙的解法,思路来源于大佬
#include<bits/stdc++.h>
using namespace std;
int i,m,n,j,k;
int a[40][40];
inline void bfs(int x,int y){//将外围的0全变为2
if(x<0 || x>n+1 || y<0 || y>n+1 || a[x][y]==1 || a[x][y]==2)return;
a[x][y]=2;
bfs(x+1,y);
bfs(x-1,y);
bfs(x,y+1);
bfs(x,y-1);
return;
}
int main(){
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
bfs(0,0);//为避免如下情况
/*//如果改为1,1 则不会进入bfs()
10
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 0 1 0 1 0 0 0 0 1
1 0 1 0 1 0 0 0 0 1
1 0 1 0 1 0 0 0 0 1
1 0 1 0 1 0 1 1 1 1
1 0 1 0 1 0 1 0 0 0
1 0 1 1 1 0 1 1 1 1
1 0 0 1 1 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
*/
for(i=1;i<=n;i++){
cout<<2-a[i][1];
for(j=2;j<=n;j++)
cout<<" "<<2-a[i][j];
cout<<endl;
}
return 0;
}
01迷宫
概括题意:每一步走不同的格子,求走的步数
#include <iostream>
#include <queue>
using namespace std;
#define N 1000001
#define Max 1001
int n,m,sx,sy;
char map[Max][Max];
int vis[Max][Max];
int dir[][2]={
{-1,0},//上
{1,0},//下
{0,-1},//左
{0,1},//右
};
struct node//记录每个点的坐标
{
int x,y;
}no[N];
void bfs(int x,int y)
{
int ans =1,h=0,t=1,tx,ty;
no[h].x=x;//入队
no[h].y=y;
vis[x][y]=1;
while(h<t)
{
for(int k=0;k<4;k++)//4 direction
{
tx=no[h].x+dir[k][0];//入队
ty = no[h].y + dir[k][1] ; //比较之前和之后是否是同一种颜色,是=》continue
if(tx<1||ty<1||tx>n||ty>n||vis[tx][ty]==1||map[no[h].x][no[h].y]==map[tx][ty]) continue;//防止越界和重复访问及走的格子为不同值
no[t].x=tx;
no[t].y=ty;
vis[tx][ty]=1;
ans++;
t++;//扩队
}
h++;//出队
}
for(int i=0;i<t;i++)
vis[no[i].x][no[i].y]=ans;
return;
}
int main(int argc, char** argv) {
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>map[i][j];
for(int i=1;i<=m;i++)
{
cin>>sx>>sy;
if(vis[sx][sy]!=0)
cout<<vis[sx][sy]<<endl;//如果查找过就直接输出
else
{
bfs(sx,sy);
cout<<vis[sx][sy]<<endl;
}
}
return 0;
}