BFS----浅尝

本文介绍了BFS(广度优先搜索)算法在处理图形结构中的应用,特别是针对01迷宫问题的解决方案。通过逐层遍历,BFS能有效地找出从起始状态到达目标状态的最短路径。文中还提供了具体实例,展示如何使用BFS将闭合圈内的0填充为2,并给出了输入输出样例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

更多模板尽在这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值